LCOV - code coverage report
Current view: directory - editor/composer/src - nsEditorSpellCheck.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 323 4 1.2 %
Date: 2012-06-02 Functions: 39 3 7.7 %

       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 Communicator client 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) 2002
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *      Kin Blas <kin@netscape.com>
      24                 :  *      Akkana Peck <akkana@netscape.com>
      25                 :  *      Charley Manske <cmanske@netscape.com>
      26                 :  *      Neil Deakin <neil@mozdevgroup.com>
      27                 :  *      Brett Wilson <brettw@gmail.com>
      28                 :  *
      29                 :  * Alternatively, the contents of this file may be used under the terms of
      30                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      31                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      32                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      33                 :  * of those above. If you wish to allow use of your version of this file only
      34                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      35                 :  * use your version of this file under the terms of the MPL, indicate your
      36                 :  * decision by deleting the provisions above and replace them with the notice
      37                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      38                 :  * the provisions above, a recipient may use your version of this file under
      39                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      40                 :  *
      41                 :  * ***** END LICENSE BLOCK ***** */
      42                 : 
      43                 : #include "nsEditorSpellCheck.h"
      44                 : 
      45                 : #include "nsStyleUtil.h"
      46                 : #include "nsIContent.h"
      47                 : #include "nsIDOMElement.h"
      48                 : #include "nsITextServicesDocument.h"
      49                 : #include "nsISpellChecker.h"
      50                 : #include "nsISelection.h"
      51                 : #include "nsIDOMRange.h"
      52                 : #include "nsIEditor.h"
      53                 : #include "nsIHTMLEditor.h"
      54                 : 
      55                 : #include "nsIComponentManager.h"
      56                 : #include "nsIContentPrefService.h"
      57                 : #include "nsServiceManagerUtils.h"
      58                 : #include "nsIChromeRegistry.h"
      59                 : #include "nsString.h"
      60                 : #include "nsReadableUtils.h"
      61                 : #include "nsITextServicesFilter.h"
      62                 : #include "nsUnicharUtils.h"
      63                 : #include "mozilla/Services.h"
      64                 : #include "mozilla/Preferences.h"
      65                 : 
      66                 : using namespace mozilla;
      67                 : 
      68                 : class UpdateDictionnaryHolder {
      69                 :   private:
      70                 :     nsEditorSpellCheck* mSpellCheck;
      71                 :   public:
      72               0 :     UpdateDictionnaryHolder(nsEditorSpellCheck* esc): mSpellCheck(esc) {
      73               0 :       if (mSpellCheck) {
      74               0 :         mSpellCheck->BeginUpdateDictionary();
      75                 :       }
      76               0 :     }
      77               0 :     ~UpdateDictionnaryHolder() {
      78               0 :       if (mSpellCheck) {
      79               0 :         mSpellCheck->EndUpdateDictionary();
      80                 :       }
      81               0 :     }
      82                 : };
      83                 : 
      84                 : #define CPS_PREF_NAME NS_LITERAL_STRING("spellcheck.lang")
      85                 : 
      86               0 : class LastDictionary MOZ_FINAL {
      87                 : public:
      88                 :   /**
      89                 :    * Store current dictionary for editor document url. Use content pref
      90                 :    * service.
      91                 :    */
      92                 :   NS_IMETHOD StoreCurrentDictionary(nsIEditor* aEditor, const nsAString& aDictionary);
      93                 : 
      94                 :   /**
      95                 :    * Get last stored current dictionary for editor document url.
      96                 :    */
      97                 :   NS_IMETHOD FetchLastDictionary(nsIEditor* aEditor, nsAString& aDictionary);
      98                 : 
      99                 :   /**
     100                 :    * Forget last current dictionary stored for editor document url.
     101                 :    */
     102                 :   NS_IMETHOD ClearCurrentDictionary(nsIEditor* aEditor);
     103                 : 
     104                 :   /**
     105                 :    * get uri of editor's document.
     106                 :    *
     107                 :    */
     108                 :   static nsresult GetDocumentURI(nsIEditor* aEditor, nsIURI * *aURI);
     109                 : };
     110                 : 
     111                 : // static
     112                 : nsresult
     113               0 : LastDictionary::GetDocumentURI(nsIEditor* aEditor, nsIURI * *aURI)
     114                 : {
     115               0 :   NS_ENSURE_ARG_POINTER(aEditor);
     116               0 :   NS_ENSURE_ARG_POINTER(aURI);
     117                 : 
     118               0 :   nsCOMPtr<nsIDOMDocument> domDoc;
     119               0 :   aEditor->GetDocument(getter_AddRefs(domDoc));
     120               0 :   NS_ENSURE_TRUE(domDoc, NS_ERROR_FAILURE);
     121                 : 
     122               0 :   nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
     123               0 :   NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
     124                 : 
     125               0 :   nsCOMPtr<nsIURI> docUri = doc->GetDocumentURI();
     126               0 :   NS_ENSURE_TRUE(docUri, NS_ERROR_FAILURE);
     127                 : 
     128               0 :   *aURI = docUri;
     129               0 :   NS_ADDREF(*aURI);
     130               0 :   return NS_OK;
     131                 : }
     132                 : 
     133                 : NS_IMETHODIMP
     134               0 : LastDictionary::FetchLastDictionary(nsIEditor* aEditor, nsAString& aDictionary)
     135                 : {
     136               0 :   NS_ENSURE_ARG_POINTER(aEditor);
     137                 : 
     138                 :   nsresult rv;
     139                 : 
     140               0 :   nsCOMPtr<nsIURI> docUri;
     141               0 :   rv = GetDocumentURI(aEditor, getter_AddRefs(docUri));
     142               0 :   NS_ENSURE_SUCCESS(rv, rv);
     143                 : 
     144                 :   nsCOMPtr<nsIContentPrefService> contentPrefService =
     145               0 :     do_GetService(NS_CONTENT_PREF_SERVICE_CONTRACTID);
     146               0 :   NS_ENSURE_TRUE(contentPrefService, NS_ERROR_NOT_AVAILABLE);
     147                 : 
     148               0 :   nsCOMPtr<nsIWritableVariant> uri = do_CreateInstance(NS_VARIANT_CONTRACTID);
     149               0 :   NS_ENSURE_TRUE(uri, NS_ERROR_OUT_OF_MEMORY);
     150               0 :   uri->SetAsISupports(docUri);
     151                 : 
     152                 :   bool hasPref;
     153               0 :   if (NS_SUCCEEDED(contentPrefService->HasPref(uri, CPS_PREF_NAME, &hasPref)) && hasPref) {
     154               0 :     nsCOMPtr<nsIVariant> pref;
     155               0 :     contentPrefService->GetPref(uri, CPS_PREF_NAME, nsnull, getter_AddRefs(pref));
     156               0 :     pref->GetAsAString(aDictionary);
     157                 :   } else {
     158               0 :     aDictionary.Truncate();
     159                 :   }
     160                 : 
     161               0 :   return NS_OK;
     162                 : }
     163                 : 
     164                 : NS_IMETHODIMP
     165               0 : LastDictionary::StoreCurrentDictionary(nsIEditor* aEditor, const nsAString& aDictionary)
     166                 : {
     167               0 :   NS_ENSURE_ARG_POINTER(aEditor);
     168                 : 
     169                 :   nsresult rv;
     170                 : 
     171               0 :   nsCOMPtr<nsIURI> docUri;
     172               0 :   rv = GetDocumentURI(aEditor, getter_AddRefs(docUri));
     173               0 :   NS_ENSURE_SUCCESS(rv, rv);
     174                 : 
     175               0 :   nsCOMPtr<nsIWritableVariant> uri = do_CreateInstance(NS_VARIANT_CONTRACTID);
     176               0 :   NS_ENSURE_TRUE(uri, NS_ERROR_OUT_OF_MEMORY);
     177               0 :   uri->SetAsISupports(docUri);
     178                 : 
     179               0 :   nsCOMPtr<nsIWritableVariant> prefValue = do_CreateInstance(NS_VARIANT_CONTRACTID);
     180               0 :   NS_ENSURE_TRUE(prefValue, NS_ERROR_OUT_OF_MEMORY);
     181               0 :   prefValue->SetAsAString(aDictionary);
     182                 : 
     183                 :   nsCOMPtr<nsIContentPrefService> contentPrefService =
     184               0 :     do_GetService(NS_CONTENT_PREF_SERVICE_CONTRACTID);
     185               0 :   NS_ENSURE_TRUE(contentPrefService, NS_ERROR_NOT_INITIALIZED);
     186                 : 
     187               0 :   return contentPrefService->SetPref(uri, CPS_PREF_NAME, prefValue);
     188                 : }
     189                 : 
     190                 : NS_IMETHODIMP
     191               0 : LastDictionary::ClearCurrentDictionary(nsIEditor* aEditor)
     192                 : {
     193               0 :   NS_ENSURE_ARG_POINTER(aEditor);
     194                 : 
     195                 :   nsresult rv;
     196                 : 
     197               0 :   nsCOMPtr<nsIURI> docUri;
     198               0 :   rv = GetDocumentURI(aEditor, getter_AddRefs(docUri));
     199               0 :   NS_ENSURE_SUCCESS(rv, rv);
     200                 : 
     201               0 :   nsCOMPtr<nsIWritableVariant> uri = do_CreateInstance(NS_VARIANT_CONTRACTID);
     202               0 :   NS_ENSURE_TRUE(uri, NS_ERROR_OUT_OF_MEMORY);
     203               0 :   uri->SetAsISupports(docUri);
     204                 : 
     205                 :   nsCOMPtr<nsIContentPrefService> contentPrefService =
     206               0 :     do_GetService(NS_CONTENT_PREF_SERVICE_CONTRACTID);
     207               0 :   NS_ENSURE_TRUE(contentPrefService, NS_ERROR_NOT_INITIALIZED);
     208                 : 
     209               0 :   return contentPrefService->RemovePref(uri, CPS_PREF_NAME);
     210                 : }
     211                 : 
     212                 : LastDictionary* nsEditorSpellCheck::gDictionaryStore = nsnull;
     213                 : 
     214               0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsEditorSpellCheck)
     215               0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsEditorSpellCheck)
     216                 : 
     217               0 : NS_INTERFACE_MAP_BEGIN(nsEditorSpellCheck)
     218               0 :   NS_INTERFACE_MAP_ENTRY(nsIEditorSpellCheck)
     219               0 :   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIEditorSpellCheck)
     220               0 :   NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsEditorSpellCheck)
     221               0 : NS_INTERFACE_MAP_END
     222                 : 
     223            1464 : NS_IMPL_CYCLE_COLLECTION_3(nsEditorSpellCheck,
     224                 :                            mEditor,
     225                 :                            mSpellChecker,
     226                 :                            mTxtSrvFilter)
     227                 : 
     228               0 : nsEditorSpellCheck::nsEditorSpellCheck()
     229                 :   : mSuggestedWordIndex(0)
     230                 :   , mDictionaryIndex(0)
     231                 :   , mEditor(nsnull)
     232               0 :   , mUpdateDictionaryRunning(false)
     233                 : {
     234               0 : }
     235                 : 
     236               0 : nsEditorSpellCheck::~nsEditorSpellCheck()
     237                 : {
     238                 :   // Make sure we blow the spellchecker away, just in
     239                 :   // case it hasn't been destroyed already.
     240               0 :   mSpellChecker = nsnull;
     241               0 : }
     242                 : 
     243                 : // The problem is that if the spell checker does not exist, we can not tell
     244                 : // which dictionaries are installed. This function works around the problem,
     245                 : // allowing callers to ask if we can spell check without actually doing so (and
     246                 : // enabling or disabling UI as necessary). This just creates a spellcheck
     247                 : // object if needed and asks it for the dictionary list.
     248                 : NS_IMETHODIMP
     249               0 : nsEditorSpellCheck::CanSpellCheck(bool* _retval)
     250                 : {
     251                 :   nsresult rv;
     252               0 :   nsCOMPtr<nsISpellChecker> spellChecker;
     253               0 :   if (! mSpellChecker) {
     254               0 :     spellChecker = do_CreateInstance(NS_SPELLCHECKER_CONTRACTID, &rv);
     255               0 :     NS_ENSURE_SUCCESS(rv, rv);
     256                 :   } else {
     257               0 :     spellChecker = mSpellChecker;
     258                 :   }
     259               0 :   nsTArray<nsString> dictList;
     260               0 :   rv = spellChecker->GetDictionaryList(&dictList);
     261               0 :   NS_ENSURE_SUCCESS(rv, rv);
     262                 : 
     263               0 :   *_retval = (dictList.Length() > 0);
     264               0 :   return NS_OK;
     265                 : }
     266                 : 
     267                 : NS_IMETHODIMP    
     268               0 : nsEditorSpellCheck::InitSpellChecker(nsIEditor* aEditor, bool aEnableSelectionChecking)
     269                 : {
     270               0 :   NS_ENSURE_TRUE(aEditor, NS_ERROR_NULL_POINTER);
     271               0 :   mEditor = aEditor;
     272                 : 
     273                 :   nsresult rv;
     274                 : 
     275               0 :   if (!gDictionaryStore) {
     276               0 :     gDictionaryStore = new LastDictionary();
     277                 :   }
     278                 : 
     279                 : 
     280                 :   // We can spell check with any editor type
     281                 :   nsCOMPtr<nsITextServicesDocument>tsDoc =
     282               0 :      do_CreateInstance("@mozilla.org/textservices/textservicesdocument;1", &rv);
     283               0 :   NS_ENSURE_SUCCESS(rv, rv);
     284                 : 
     285               0 :   NS_ENSURE_TRUE(tsDoc, NS_ERROR_NULL_POINTER);
     286                 : 
     287               0 :   tsDoc->SetFilter(mTxtSrvFilter);
     288                 : 
     289                 :   // Pass the editor to the text services document
     290               0 :   rv = tsDoc->InitWithEditor(aEditor);
     291               0 :   NS_ENSURE_SUCCESS(rv, rv);
     292                 : 
     293               0 :   if (aEnableSelectionChecking) {
     294                 :     // Find out if the section is collapsed or not.
     295                 :     // If it isn't, we want to spellcheck just the selection.
     296                 : 
     297               0 :     nsCOMPtr<nsISelection> selection;
     298                 : 
     299               0 :     rv = aEditor->GetSelection(getter_AddRefs(selection));
     300               0 :     NS_ENSURE_SUCCESS(rv, rv);
     301               0 :     NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
     302                 : 
     303               0 :     PRInt32 count = 0;
     304                 : 
     305               0 :     rv = selection->GetRangeCount(&count);
     306               0 :     NS_ENSURE_SUCCESS(rv, rv);
     307                 : 
     308               0 :     if (count > 0) {
     309               0 :       nsCOMPtr<nsIDOMRange> range;
     310                 : 
     311               0 :       rv = selection->GetRangeAt(0, getter_AddRefs(range));
     312               0 :       NS_ENSURE_SUCCESS(rv, rv);
     313                 : 
     314               0 :       bool collapsed = false;
     315               0 :       rv = range->GetCollapsed(&collapsed);
     316               0 :       NS_ENSURE_SUCCESS(rv, rv);
     317                 : 
     318               0 :       if (!collapsed) {
     319                 :         // We don't want to touch the range in the selection,
     320                 :         // so create a new copy of it.
     321                 : 
     322               0 :         nsCOMPtr<nsIDOMRange> rangeBounds;
     323               0 :         rv =  range->CloneRange(getter_AddRefs(rangeBounds));
     324               0 :         NS_ENSURE_SUCCESS(rv, rv);
     325               0 :         NS_ENSURE_TRUE(rangeBounds, NS_ERROR_FAILURE);
     326                 : 
     327                 :         // Make sure the new range spans complete words.
     328                 : 
     329               0 :         rv = tsDoc->ExpandRangeToWordBoundaries(rangeBounds);
     330               0 :         NS_ENSURE_SUCCESS(rv, rv);
     331                 : 
     332                 :         // Now tell the text services that you only want
     333                 :         // to iterate over the text in this range.
     334                 : 
     335               0 :         rv = tsDoc->SetExtent(rangeBounds);
     336               0 :         NS_ENSURE_SUCCESS(rv, rv);
     337                 :       }
     338                 :     }
     339                 :   }
     340                 : 
     341               0 :   mSpellChecker = do_CreateInstance(NS_SPELLCHECKER_CONTRACTID, &rv);
     342               0 :   NS_ENSURE_SUCCESS(rv, rv);
     343                 : 
     344               0 :   NS_ENSURE_TRUE(mSpellChecker, NS_ERROR_NULL_POINTER);
     345                 : 
     346               0 :   rv = mSpellChecker->SetDocument(tsDoc, true);
     347               0 :   NS_ENSURE_SUCCESS(rv, rv);
     348                 : 
     349                 :   // do not fail if UpdateCurrentDictionary fails because this method may
     350                 :   // succeed later.
     351               0 :   UpdateCurrentDictionary();
     352               0 :   return NS_OK;
     353                 : }
     354                 : 
     355                 : NS_IMETHODIMP    
     356               0 : nsEditorSpellCheck::GetNextMisspelledWord(PRUnichar **aNextMisspelledWord)
     357                 : {
     358               0 :   NS_ENSURE_TRUE(mSpellChecker, NS_ERROR_NOT_INITIALIZED);
     359                 : 
     360               0 :   nsAutoString nextMisspelledWord;
     361                 :   
     362               0 :   DeleteSuggestedWordList();
     363                 :   // Beware! This may flush notifications via synchronous
     364                 :   // ScrollSelectionIntoView.
     365               0 :   nsresult rv = mSpellChecker->NextMisspelledWord(nextMisspelledWord,
     366               0 :                                                   &mSuggestedWordList);
     367                 : 
     368               0 :   *aNextMisspelledWord = ToNewUnicode(nextMisspelledWord);
     369               0 :   return rv;
     370                 : }
     371                 : 
     372                 : NS_IMETHODIMP    
     373               0 : nsEditorSpellCheck::GetSuggestedWord(PRUnichar **aSuggestedWord)
     374                 : {
     375               0 :   nsAutoString word;
     376               0 :   if ( mSuggestedWordIndex < PRInt32(mSuggestedWordList.Length()))
     377                 :   {
     378               0 :     *aSuggestedWord = ToNewUnicode(mSuggestedWordList[mSuggestedWordIndex]);
     379               0 :     mSuggestedWordIndex++;
     380                 :   } else {
     381                 :     // A blank string signals that there are no more strings
     382               0 :     *aSuggestedWord = ToNewUnicode(EmptyString());
     383                 :   }
     384               0 :   return NS_OK;
     385                 : }
     386                 : 
     387                 : NS_IMETHODIMP    
     388               0 : nsEditorSpellCheck::CheckCurrentWord(const PRUnichar *aSuggestedWord,
     389                 :                                      bool *aIsMisspelled)
     390                 : {
     391               0 :   NS_ENSURE_TRUE(mSpellChecker, NS_ERROR_NOT_INITIALIZED);
     392                 : 
     393               0 :   DeleteSuggestedWordList();
     394               0 :   return mSpellChecker->CheckWord(nsDependentString(aSuggestedWord),
     395               0 :                                   aIsMisspelled, &mSuggestedWordList);
     396                 : }
     397                 : 
     398                 : NS_IMETHODIMP    
     399               0 : nsEditorSpellCheck::CheckCurrentWordNoSuggest(const PRUnichar *aSuggestedWord,
     400                 :                                               bool *aIsMisspelled)
     401                 : {
     402               0 :   NS_ENSURE_TRUE(mSpellChecker, NS_ERROR_NOT_INITIALIZED);
     403                 : 
     404               0 :   return mSpellChecker->CheckWord(nsDependentString(aSuggestedWord),
     405               0 :                                   aIsMisspelled, nsnull);
     406                 : }
     407                 : 
     408                 : NS_IMETHODIMP    
     409               0 : nsEditorSpellCheck::ReplaceWord(const PRUnichar *aMisspelledWord,
     410                 :                                 const PRUnichar *aReplaceWord,
     411                 :                                 bool             allOccurrences)
     412                 : {
     413               0 :   NS_ENSURE_TRUE(mSpellChecker, NS_ERROR_NOT_INITIALIZED);
     414                 : 
     415               0 :   return mSpellChecker->Replace(nsDependentString(aMisspelledWord),
     416               0 :                                 nsDependentString(aReplaceWord), allOccurrences);
     417                 : }
     418                 : 
     419                 : NS_IMETHODIMP    
     420               0 : nsEditorSpellCheck::IgnoreWordAllOccurrences(const PRUnichar *aWord)
     421                 : {
     422               0 :   NS_ENSURE_TRUE(mSpellChecker, NS_ERROR_NOT_INITIALIZED);
     423                 : 
     424               0 :   return mSpellChecker->IgnoreAll(nsDependentString(aWord));
     425                 : }
     426                 : 
     427                 : NS_IMETHODIMP    
     428               0 : nsEditorSpellCheck::GetPersonalDictionary()
     429                 : {
     430               0 :   NS_ENSURE_TRUE(mSpellChecker, NS_ERROR_NOT_INITIALIZED);
     431                 : 
     432                 :    // We can spell check with any editor type
     433               0 :   mDictionaryList.Clear();
     434               0 :   mDictionaryIndex = 0;
     435               0 :   return mSpellChecker->GetPersonalDictionary(&mDictionaryList);
     436                 : }
     437                 : 
     438                 : NS_IMETHODIMP    
     439               0 : nsEditorSpellCheck::GetPersonalDictionaryWord(PRUnichar **aDictionaryWord)
     440                 : {
     441               0 :   if ( mDictionaryIndex < PRInt32( mDictionaryList.Length()))
     442                 :   {
     443               0 :     *aDictionaryWord = ToNewUnicode(mDictionaryList[mDictionaryIndex]);
     444               0 :     mDictionaryIndex++;
     445                 :   } else {
     446                 :     // A blank string signals that there are no more strings
     447               0 :     *aDictionaryWord = ToNewUnicode(EmptyString());
     448                 :   }
     449                 : 
     450               0 :   return NS_OK;
     451                 : }
     452                 : 
     453                 : NS_IMETHODIMP    
     454               0 : nsEditorSpellCheck::AddWordToDictionary(const PRUnichar *aWord)
     455                 : {
     456               0 :   NS_ENSURE_TRUE(mSpellChecker, NS_ERROR_NOT_INITIALIZED);
     457                 : 
     458               0 :   return mSpellChecker->AddWordToPersonalDictionary(nsDependentString(aWord));
     459                 : }
     460                 : 
     461                 : NS_IMETHODIMP    
     462               0 : nsEditorSpellCheck::RemoveWordFromDictionary(const PRUnichar *aWord)
     463                 : {
     464               0 :   NS_ENSURE_TRUE(mSpellChecker, NS_ERROR_NOT_INITIALIZED);
     465                 : 
     466               0 :   return mSpellChecker->RemoveWordFromPersonalDictionary(nsDependentString(aWord));
     467                 : }
     468                 : 
     469                 : NS_IMETHODIMP    
     470               0 : nsEditorSpellCheck::GetDictionaryList(PRUnichar ***aDictionaryList, PRUint32 *aCount)
     471                 : {
     472               0 :   NS_ENSURE_TRUE(mSpellChecker, NS_ERROR_NOT_INITIALIZED);
     473                 : 
     474               0 :   NS_ENSURE_TRUE(aDictionaryList && aCount, NS_ERROR_NULL_POINTER);
     475                 : 
     476               0 :   *aDictionaryList = 0;
     477               0 :   *aCount          = 0;
     478                 : 
     479               0 :   nsTArray<nsString> dictList;
     480                 : 
     481               0 :   nsresult rv = mSpellChecker->GetDictionaryList(&dictList);
     482                 : 
     483               0 :   NS_ENSURE_SUCCESS(rv, rv);
     484                 : 
     485               0 :   PRUnichar **tmpPtr = 0;
     486                 : 
     487               0 :   if (dictList.Length() < 1)
     488                 :   {
     489                 :     // If there are no dictionaries, return an array containing
     490                 :     // one element and a count of one.
     491                 : 
     492               0 :     tmpPtr = (PRUnichar **)nsMemory::Alloc(sizeof(PRUnichar *));
     493                 : 
     494               0 :     NS_ENSURE_TRUE(tmpPtr, NS_ERROR_OUT_OF_MEMORY);
     495                 : 
     496               0 :     *tmpPtr          = 0;
     497               0 :     *aDictionaryList = tmpPtr;
     498               0 :     *aCount          = 0;
     499                 : 
     500               0 :     return NS_OK;
     501                 :   }
     502                 : 
     503               0 :   tmpPtr = (PRUnichar **)nsMemory::Alloc(sizeof(PRUnichar *) * dictList.Length());
     504                 : 
     505               0 :   NS_ENSURE_TRUE(tmpPtr, NS_ERROR_OUT_OF_MEMORY);
     506                 : 
     507               0 :   *aDictionaryList = tmpPtr;
     508               0 :   *aCount          = dictList.Length();
     509                 : 
     510                 :   PRUint32 i;
     511                 : 
     512               0 :   for (i = 0; i < *aCount; i++)
     513                 :   {
     514               0 :     tmpPtr[i] = ToNewUnicode(dictList[i]);
     515                 :   }
     516                 : 
     517               0 :   return rv;
     518                 : }
     519                 : 
     520                 : NS_IMETHODIMP    
     521               0 : nsEditorSpellCheck::GetCurrentDictionary(nsAString& aDictionary)
     522                 : {
     523               0 :   NS_ENSURE_TRUE(mSpellChecker, NS_ERROR_NOT_INITIALIZED);
     524                 : 
     525               0 :   return mSpellChecker->GetCurrentDictionary(aDictionary);
     526                 : }
     527                 : 
     528                 : NS_IMETHODIMP    
     529               0 : nsEditorSpellCheck::SetCurrentDictionary(const nsAString& aDictionary)
     530                 : {
     531               0 :   NS_ENSURE_TRUE(mSpellChecker, NS_ERROR_NOT_INITIALIZED);
     532                 : 
     533               0 :   if (!mUpdateDictionaryRunning) {
     534                 : 
     535               0 :     nsDefaultStringComparator comparator;
     536               0 :     nsAutoString langCode;
     537               0 :     PRInt32 dashIdx = aDictionary.FindChar('-');
     538               0 :     if (dashIdx != -1) {
     539               0 :       langCode.Assign(Substring(aDictionary, 0, dashIdx));
     540                 :     } else {
     541               0 :       langCode.Assign(aDictionary);
     542                 :     }
     543                 : 
     544               0 :     if (mPreferredLang.IsEmpty() || !nsStyleUtil::DashMatchCompare(mPreferredLang, langCode, comparator)) {
     545                 :       // When user sets dictionary manually, we store this value associated
     546                 :       // with editor url.
     547               0 :       gDictionaryStore->StoreCurrentDictionary(mEditor, aDictionary);
     548                 :     } else {
     549                 :       // If user sets a dictionary matching (even partially), lang defined by
     550                 :       // document, we consider content pref has been canceled, and we clear it.
     551               0 :       gDictionaryStore->ClearCurrentDictionary(mEditor);
     552                 :     }
     553                 : 
     554                 :     // Also store it in as a preference. It will be used as a default value
     555                 :     // when everything else fails.
     556               0 :     Preferences::SetString("spellchecker.dictionary", aDictionary);
     557                 :   }
     558               0 :   return mSpellChecker->SetCurrentDictionary(aDictionary);
     559                 : }
     560                 : 
     561                 : NS_IMETHODIMP
     562               0 : nsEditorSpellCheck::CheckCurrentDictionary()
     563                 : {
     564               0 :   mSpellChecker->CheckCurrentDictionary();
     565                 : 
     566                 :   // Check if our current dictionary is still available.
     567               0 :   nsAutoString currentDictionary;
     568               0 :   nsresult rv = GetCurrentDictionary(currentDictionary);
     569               0 :   if (NS_SUCCEEDED(rv) && !currentDictionary.IsEmpty()) {
     570               0 :     return NS_OK;
     571                 :   }
     572                 : 
     573                 :   // If our preferred current dictionary has gone, pick another one.
     574               0 :   nsTArray<nsString> dictList;
     575               0 :   rv = mSpellChecker->GetDictionaryList(&dictList);
     576               0 :   NS_ENSURE_SUCCESS(rv, rv);
     577                 : 
     578               0 :   if (dictList.Length() > 0) {
     579               0 :     rv = SetCurrentDictionary(dictList[0]);
     580               0 :     NS_ENSURE_SUCCESS(rv, rv);
     581                 :   }
     582                 : 
     583               0 :   return NS_OK;
     584                 : }
     585                 : 
     586                 : NS_IMETHODIMP    
     587               0 : nsEditorSpellCheck::UninitSpellChecker()
     588                 : {
     589               0 :   NS_ENSURE_TRUE(mSpellChecker, NS_ERROR_NOT_INITIALIZED);
     590                 : 
     591                 :   // Cleanup - kill the spell checker
     592               0 :   DeleteSuggestedWordList();
     593               0 :   mDictionaryList.Clear();
     594               0 :   mDictionaryIndex = 0;
     595               0 :   mSpellChecker = 0;
     596               0 :   return NS_OK;
     597                 : }
     598                 : 
     599                 : 
     600                 : /* void setFilter (in nsITextServicesFilter filter); */
     601                 : NS_IMETHODIMP 
     602               0 : nsEditorSpellCheck::SetFilter(nsITextServicesFilter *filter)
     603                 : {
     604               0 :   mTxtSrvFilter = filter;
     605               0 :   return NS_OK;
     606                 : }
     607                 : 
     608                 : nsresult    
     609               0 : nsEditorSpellCheck::DeleteSuggestedWordList()
     610                 : {
     611               0 :   mSuggestedWordList.Clear();
     612               0 :   mSuggestedWordIndex = 0;
     613               0 :   return NS_OK;
     614                 : }
     615                 : 
     616                 : NS_IMETHODIMP
     617               0 : nsEditorSpellCheck::UpdateCurrentDictionary()
     618                 : {
     619                 :   nsresult rv;
     620                 : 
     621               0 :   UpdateDictionnaryHolder holder(this);
     622                 : 
     623                 :   // Get language with html5 algorithm
     624               0 :   nsCOMPtr<nsIContent> rootContent;
     625               0 :   nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(mEditor);
     626               0 :   if (htmlEditor) {
     627               0 :     rootContent = htmlEditor->GetActiveEditingHost();
     628                 :   } else {
     629               0 :     nsCOMPtr<nsIDOMElement> rootElement;
     630               0 :     rv = mEditor->GetRootElement(getter_AddRefs(rootElement));
     631               0 :     NS_ENSURE_SUCCESS(rv, rv);
     632               0 :     rootContent = do_QueryInterface(rootElement);
     633                 :   }
     634               0 :   NS_ENSURE_TRUE(rootContent, NS_ERROR_FAILURE);
     635                 : 
     636               0 :   mPreferredLang.Truncate();
     637               0 :   rootContent->GetLang(mPreferredLang);
     638                 : 
     639                 :   // Tell the spellchecker what dictionary to use:
     640                 : 
     641                 :   // First try to get dictionary from content prefs. If we have one, do not got
     642                 :   // further. Use this exact dictionary.
     643               0 :   nsAutoString dictName;
     644               0 :   rv = gDictionaryStore->FetchLastDictionary(mEditor, dictName);
     645               0 :   if (NS_SUCCEEDED(rv) && !dictName.IsEmpty()) {
     646               0 :     if (NS_FAILED(SetCurrentDictionary(dictName))) { 
     647                 :       // may be dictionary was uninstalled ?
     648               0 :       gDictionaryStore->ClearCurrentDictionary(mEditor);
     649                 :     }
     650               0 :     return NS_OK;
     651                 :   }
     652                 : 
     653               0 :   if (mPreferredLang.IsEmpty()) {
     654               0 :     nsCOMPtr<nsIDocument> doc = rootContent->GetCurrentDoc();
     655               0 :     NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
     656               0 :     doc->GetContentLanguage(mPreferredLang);
     657                 :   }
     658                 : 
     659                 :   // Then, try to use language computed from element
     660               0 :   if (!mPreferredLang.IsEmpty()) {
     661               0 :     dictName.Assign(mPreferredLang);
     662                 :   }
     663                 : 
     664                 :   // otherwise, get language from preferences
     665               0 :   nsAutoString preferedDict(Preferences::GetLocalizedString("spellchecker.dictionary"));
     666               0 :   if (dictName.IsEmpty()) {
     667               0 :     dictName.Assign(preferedDict);
     668                 :   }
     669                 : 
     670               0 :   if (dictName.IsEmpty())
     671                 :   {
     672                 :     // Prefs didn't give us a dictionary name, so just get the current
     673                 :     // locale and use that as the default dictionary name!
     674                 : 
     675                 :     nsCOMPtr<nsIXULChromeRegistry> packageRegistry =
     676               0 :       mozilla::services::GetXULChromeRegistryService();
     677                 : 
     678               0 :     if (packageRegistry) {
     679               0 :       nsCAutoString utf8DictName;
     680               0 :       rv = packageRegistry->GetSelectedLocale(NS_LITERAL_CSTRING("global"),
     681               0 :                                               utf8DictName);
     682               0 :       AppendUTF8toUTF16(utf8DictName, dictName);
     683                 :     }
     684                 :   }
     685                 : 
     686               0 :   if (NS_SUCCEEDED(rv) && !dictName.IsEmpty()) {
     687               0 :     rv = SetCurrentDictionary(dictName);
     688               0 :     if (NS_FAILED(rv)) {
     689                 :       // required dictionary was not available. Try to get a dictionary
     690                 :       // matching at least language part of dictName: 
     691                 : 
     692               0 :       nsAutoString langCode;
     693               0 :       PRInt32 dashIdx = dictName.FindChar('-');
     694               0 :       if (dashIdx != -1) {
     695               0 :         langCode.Assign(Substring(dictName, 0, dashIdx));
     696                 :       } else {
     697               0 :         langCode.Assign(dictName);
     698                 :       }
     699                 : 
     700               0 :       nsDefaultStringComparator comparator;
     701                 : 
     702                 :       // try dictionary.spellchecker preference if it starts with langCode (and
     703                 :       // if we haven't tried it already)
     704               0 :       if (!preferedDict.IsEmpty() && !dictName.Equals(preferedDict) && 
     705               0 :           nsStyleUtil::DashMatchCompare(preferedDict, langCode, comparator)) {
     706               0 :         rv = SetCurrentDictionary(preferedDict);
     707                 :       }
     708                 : 
     709                 :       // Otherwise, try langCode (if we haven't tried it already)
     710               0 :       if (NS_FAILED(rv)) {
     711               0 :         if (!dictName.Equals(langCode) && !preferedDict.Equals(langCode)) {
     712               0 :           rv = SetCurrentDictionary(langCode);
     713                 :         }
     714                 :       }
     715                 : 
     716                 :       // Otherwise, try any available dictionary aa-XX
     717               0 :       if (NS_FAILED(rv)) {
     718                 :         // loop over avaible dictionaries; if we find one with required
     719                 :         // language, use it
     720               0 :         nsTArray<nsString> dictList;
     721               0 :         rv = mSpellChecker->GetDictionaryList(&dictList);
     722               0 :         NS_ENSURE_SUCCESS(rv, rv);
     723               0 :         PRInt32 i, count = dictList.Length();
     724               0 :         for (i = 0; i < count; i++) {
     725               0 :           nsAutoString dictStr(dictList.ElementAt(i));
     726                 : 
     727               0 :           if (dictStr.Equals(dictName) ||
     728               0 :               dictStr.Equals(preferedDict) ||
     729               0 :               dictStr.Equals(langCode)) {
     730                 :             // We have already tried it
     731               0 :             continue;
     732                 :           }
     733                 : 
     734               0 :           if (nsStyleUtil::DashMatchCompare(dictStr, langCode, comparator) &&
     735               0 :               NS_SUCCEEDED(SetCurrentDictionary(dictStr))) {
     736                 :               break;
     737                 :           }
     738                 :         }
     739                 :       }
     740                 :     }
     741                 :   }
     742                 : 
     743                 :   // If we have not set dictionary, and the editable element doesn't have a
     744                 :   // lang attribute, we try to get a dictionary. First try, en-US. If it does
     745                 :   // not work, pick the first one.
     746               0 :   if (mPreferredLang.IsEmpty()) {
     747               0 :     nsAutoString currentDictionary;
     748               0 :     rv = GetCurrentDictionary(currentDictionary);
     749               0 :     if (NS_FAILED(rv) || currentDictionary.IsEmpty()) {
     750               0 :       rv = SetCurrentDictionary(NS_LITERAL_STRING("en-US"));
     751               0 :       if (NS_FAILED(rv)) {
     752               0 :         nsTArray<nsString> dictList;
     753               0 :         rv = mSpellChecker->GetDictionaryList(&dictList);
     754               0 :         if (NS_SUCCEEDED(rv) && dictList.Length() > 0) {
     755               0 :           SetCurrentDictionary(dictList[0]);
     756                 :         }
     757                 :       }
     758                 :     }
     759                 :   }
     760                 : 
     761                 :   // If an error was thrown while setting the dictionary, just
     762                 :   // fail silently so that the spellchecker dialog is allowed to come
     763                 :   // up. The user can manually reset the language to their choice on
     764                 :   // the dialog if it is wrong.
     765                 : 
     766               0 :   DeleteSuggestedWordList();
     767                 : 
     768               0 :   return NS_OK;
     769                 : }
     770                 : 
     771                 : void 
     772            1403 : nsEditorSpellCheck::ShutDown() {
     773            1403 :   delete gDictionaryStore;
     774            5795 : }

Generated by: LCOV version 1.7