Bug 880864 - User dictionary (persdict.dat) read on main thread. r=Ehsan,r=mayhemer

This commit is contained in:
Roberto A. Vitillo 2014-04-22 04:02:00 +02:00
Родитель 79a37b2311
Коммит bc9c36d0be
2 изменённых файлов: 142 добавлений и 21 удалений

Просмотреть файл

@ -17,6 +17,8 @@
#include "nsNetUtil.h"
#include "nsStringEnumerator.h"
#include "nsUnicharInputStream.h"
#include "nsIRunnable.h"
#include "nsThreadUtils.h"
#define MOZ_PERSONAL_DICT_NAME "persdict.dat"
@ -47,8 +49,33 @@ NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTION_1(mozPersonalDictionary, mEncoder)
class mozPersonalDictionaryLoader MOZ_FINAL : public nsRunnable
{
public:
mozPersonalDictionaryLoader(mozPersonalDictionary *dict) : mDict(dict)
{
}
NS_IMETHOD Run()
{
if (!NS_IsMainThread()) {
mDict->SyncLoad();
// Release refptr on the mainthread
NS_DispatchToMainThread(this);
}
return NS_OK;
}
private:
nsRefPtr<mozPersonalDictionary> mDict;
};
mozPersonalDictionary::mozPersonalDictionary()
: mDirty(false)
: mDirty(false),
mIsLoaded(false),
mMonitor("mozPersonalDictionary::mMonitor")
{
}
@ -69,39 +96,99 @@ nsresult mozPersonalDictionary::Init()
NS_ENSURE_SUCCESS(rv, rv);
Load();
return NS_OK;
}
/* void Load (); */
void mozPersonalDictionary::WaitForLoad()
{
if (mIsLoaded) {
return;
}
mozilla::MonitorAutoLock mon(mMonitor);
if (!mIsLoaded) {
mon.Wait();
}
}
NS_IMETHODIMP mozPersonalDictionary::Load()
{
nsresult rv;
mozilla::MonitorAutoLock mon(mMonitor);
if (mIsLoaded) {
return NS_OK;
}
nsCOMPtr<nsIEventTarget> target = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIRunnable> runnable = new mozPersonalDictionaryLoader(this);
rv = target->Dispatch(runnable, NS_DISPATCH_NORMAL);
return rv;
}
void mozPersonalDictionary::SyncLoad()
{
MOZ_ASSERT(!NS_IsMainThread());
mozilla::MonitorAutoLock mon(mMonitor);
if (mIsLoaded) {
return;
}
SyncLoadInternal();
mIsLoaded = true;
mon.Notify();
}
void mozPersonalDictionary::SyncLoadInternal()
{
MOZ_ASSERT(!NS_IsMainThread());
//FIXME Deinst -- get dictionary name from prefs;
nsresult res;
nsresult rv;
nsCOMPtr<nsIFile> theFile;
bool dictExists;
res = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(theFile));
if(NS_FAILED(res)) return res;
if(!theFile)return NS_ERROR_FAILURE;
res = theFile->Append(NS_LITERAL_STRING(MOZ_PERSONAL_DICT_NAME));
if(NS_FAILED(res)) return res;
res = theFile->Exists(&dictExists);
if(NS_FAILED(res)) return res;
rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(theFile));
if (NS_FAILED(rv)) {
return;
}
if (!theFile) {
return;
}
rv = theFile->Append(NS_LITERAL_STRING(MOZ_PERSONAL_DICT_NAME));
if (NS_FAILED(rv)) {
return;
}
rv = theFile->Exists(&dictExists);
if (NS_FAILED(rv)) {
return;
}
if (!dictExists) {
// Nothing is really wrong...
return NS_OK;
return;
}
nsCOMPtr<nsIInputStream> inStream;
NS_NewLocalFileInputStream(getter_AddRefs(inStream), theFile);
nsCOMPtr<nsIUnicharInputStream> convStream;
res = nsSimpleUnicharStreamFactory::GetInstance()->
rv = nsSimpleUnicharStreamFactory::GetInstance()->
CreateInstanceFromUTF8Stream(inStream, getter_AddRefs(convStream));
if(NS_FAILED(res)) return res;
if (NS_FAILED(rv)) {
return;
}
// we're rereading to get rid of the old data -- we shouldn't have any, but...
mDictionaryTable.Clear();
@ -123,8 +210,6 @@ NS_IMETHODIMP mozPersonalDictionary::Load()
}
} while(!done);
mDirty = false;
return res;
}
// A little helper function to add the key to the list.
@ -143,6 +228,7 @@ NS_IMETHODIMP mozPersonalDictionary::Save()
nsCOMPtr<nsIFile> theFile;
nsresult res;
WaitForLoad();
if(!mDirty) return NS_OK;
//FIXME Deinst -- get dictionary name from prefs;
@ -188,6 +274,8 @@ NS_IMETHODIMP mozPersonalDictionary::GetWordList(nsIStringEnumerator **aWords)
NS_ENSURE_ARG_POINTER(aWords);
*aWords = nullptr;
WaitForLoad();
nsTArray<nsString> *array = new nsTArray<nsString>(mDictionaryTable.Count());
if (!array)
return NS_ERROR_OUT_OF_MEMORY;
@ -205,6 +293,8 @@ NS_IMETHODIMP mozPersonalDictionary::Check(const char16_t *aWord, const char16_t
NS_ENSURE_ARG_POINTER(aWord);
NS_ENSURE_ARG_POINTER(aResult);
WaitForLoad();
*aResult = (mDictionaryTable.GetEntry(aWord) || mIgnoreTable.GetEntry(aWord));
return NS_OK;
}
@ -212,6 +302,8 @@ NS_IMETHODIMP mozPersonalDictionary::Check(const char16_t *aWord, const char16_t
/* void AddWord (in wstring word); */
NS_IMETHODIMP mozPersonalDictionary::AddWord(const char16_t *aWord, const char16_t *aLang)
{
WaitForLoad();
mDictionaryTable.PutEntry(aWord);
mDirty = true;
return NS_OK;
@ -220,6 +312,8 @@ NS_IMETHODIMP mozPersonalDictionary::AddWord(const char16_t *aWord, const char16
/* void RemoveWord (in wstring word); */
NS_IMETHODIMP mozPersonalDictionary::RemoveWord(const char16_t *aWord, const char16_t *aLang)
{
WaitForLoad();
mDictionaryTable.RemoveEntry(aWord);
mDirty = true;
return NS_OK;
@ -237,6 +331,8 @@ NS_IMETHODIMP mozPersonalDictionary::IgnoreWord(const char16_t *aWord)
/* void EndSession (); */
NS_IMETHODIMP mozPersonalDictionary::EndSession()
{
WaitForLoad();
Save(); // save any custom words at the end of a spell check session
mIgnoreTable.Clear();
return NS_OK;
@ -264,7 +360,9 @@ NS_IMETHODIMP mozPersonalDictionary::GetCorrection(const char16_t *word, char16_
NS_IMETHODIMP mozPersonalDictionary::Observe(nsISupports *aSubject, const char *aTopic, const char16_t *aData)
{
if (!nsCRT::strcmp(aTopic, "profile-do-change")) {
Load(); // load automatically clears out the existing dictionary table
WaitForLoad();
mIsLoaded = false;
Load(); // load automatically clears out the existing dictionary table
} else if (!nsCRT::strcmp(aTopic, "profile-before-change")) {
Save();
}

Просмотреть файл

@ -17,6 +17,7 @@
#include "nsCRT.h"
#include "nsCycleCollectionParticipant.h"
#include "nsHashKeys.h"
#include <mozilla/Monitor.h>
#define MOZ_PERSONALDICTIONARY_CONTRACTID "@mozilla.org/spellchecker/personaldictionary;1"
#define MOZ_PERSONALDICTIONARY_CID \
@ -24,6 +25,8 @@
0X7EF52EAF, 0XB7E1, 0X462B, \
{ 0X87, 0XE2, 0X5D, 0X1D, 0XBA, 0XCA, 0X90, 0X48 } }
class mozPersonalDictionaryLoader;
class mozPersonalDictionary : public mozIPersonalDictionary,
public nsIObserver,
public nsSupportsWeakReference
@ -40,10 +43,30 @@ public:
nsresult Init();
protected:
bool mDirty; /* has the dictionary been modified */
/* has the dictionary been modified */
bool mDirty;
/* true if the dictionary has been loaded from disk */
bool mIsLoaded;
mozilla::Monitor mMonitor;
nsTHashtable<nsUnicharPtrHashKey> mDictionaryTable;
nsTHashtable<nsUnicharPtrHashKey> mIgnoreTable;
nsCOMPtr<nsIUnicodeEncoder> mEncoder; /*Encoder to use to compare with spellchecker word */
/*Encoder to use to compare with spellchecker word */
nsCOMPtr<nsIUnicodeEncoder> mEncoder;
private:
/* wait for the asynchronous load of the dictionary to be completed */
void WaitForLoad();
/* enter the monitor before starting a synchronous load off the main-thread */
void SyncLoad();
/* perform a synchronous load of the dictionary from disk */
void SyncLoadInternal();
friend class mozPersonalDictionaryLoader;
};
#endif