зеркало из https://github.com/mozilla/gecko-dev.git
Bug 880864 - User dictionary (persdict.dat) read on main thread. r=mayhemer
This commit is contained in:
Родитель
fe7b5cef61
Коммит
27a423ebef
|
@ -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(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")
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -64,43 +91,123 @@ nsresult mozPersonalDictionary::Init()
|
|||
NS_ENSURE_STATE(svc);
|
||||
// we want to reload the dictionary if the profile switches
|
||||
nsresult rv = svc->AddObserver(this, "profile-do-change", true);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = svc->AddObserver(this, "profile-before-change", true);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
Load();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* void Load (); */
|
||||
NS_IMETHODIMP mozPersonalDictionary::Load()
|
||||
void mozPersonalDictionary::WaitForLoad()
|
||||
{
|
||||
//FIXME Deinst -- get dictionary name from prefs;
|
||||
nsresult res;
|
||||
nsCOMPtr<nsIFile> theFile;
|
||||
bool dictExists;
|
||||
if (mIsLoaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
mozilla::MonitorAutoLock mon(mMonitor);
|
||||
|
||||
if (!dictExists) {
|
||||
// Nothing is really wrong...
|
||||
if (!mIsLoaded) {
|
||||
mon.Wait();
|
||||
}
|
||||
}
|
||||
|
||||
nsresult mozPersonalDictionary::LoadInternal()
|
||||
{
|
||||
nsresult rv;
|
||||
mozilla::MonitorAutoLock mon(mMonitor);
|
||||
|
||||
if (mIsLoaded) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(mFile));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (!mFile) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
rv = mFile->Append(NS_LITERAL_STRING(MOZ_PERSONAL_DICT_NAME));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIEventTarget> target = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIRunnable> runnable = new mozPersonalDictionaryLoader(this);
|
||||
rv = target->Dispatch(runnable, NS_DISPATCH_NORMAL);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP mozPersonalDictionary::Load()
|
||||
{
|
||||
nsresult rv = LoadInternal();
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
mIsLoaded = true;
|
||||
}
|
||||
|
||||
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 rv;
|
||||
bool dictExists;
|
||||
|
||||
rv = mFile->Exists(&dictExists);
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dictExists) {
|
||||
// Nothing is really wrong...
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInputStream> inStream;
|
||||
NS_NewLocalFileInputStream(getter_AddRefs(inStream), theFile);
|
||||
NS_NewLocalFileInputStream(getter_AddRefs(inStream), mFile);
|
||||
|
||||
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 +230,6 @@ NS_IMETHODIMP mozPersonalDictionary::Load()
|
|||
}
|
||||
} while(!done);
|
||||
mDirty = false;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// A little helper function to add the key to the list.
|
||||
|
@ -143,6 +248,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 +294,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 +313,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 +322,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 +332,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 +351,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,6 +380,10 @@ 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")) {
|
||||
// The observer is registered in Init() which calls Load and in turn
|
||||
// LoadInternal(); i.e. Observe() can't be called before Load().
|
||||
WaitForLoad();
|
||||
mIsLoaded = false;
|
||||
Load(); // load automatically clears out the existing dictionary table
|
||||
} else if (!nsCRT::strcmp(aTopic, "profile-before-change")) {
|
||||
Save();
|
||||
|
|
|
@ -16,6 +16,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 \
|
||||
|
@ -23,6 +24,8 @@
|
|||
0X7EF52EAF, 0XB7E1, 0X462B, \
|
||||
{ 0X87, 0XE2, 0X5D, 0X1D, 0XBA, 0XCA, 0X90, 0X48 } }
|
||||
|
||||
class mozPersonalDictionaryLoader;
|
||||
|
||||
class mozPersonalDictionary : public mozIPersonalDictionary,
|
||||
public nsIObserver,
|
||||
public nsSupportsWeakReference
|
||||
|
@ -39,10 +42,35 @@ 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;
|
||||
|
||||
nsCOMPtr<nsIFile> mFile;
|
||||
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();
|
||||
|
||||
/* launch an asynchrounous load of the dictionary from the main-thread
|
||||
* after successfully initializing mFile with the path of the dictionary */
|
||||
nsresult LoadInternal();
|
||||
|
||||
/* perform a synchronous load of the dictionary from disk */
|
||||
void SyncLoadInternal();
|
||||
|
||||
friend class mozPersonalDictionaryLoader;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
content quitter chrome/quitter/content/
|
||||
component {c235a986-5ac1-4f28-ad73-825dae9bad90} components/QuitterObserver.js
|
||||
contract @mozilla.org/quitter-observer;1 {c235a986-5ac1-4f28-ad73-825dae9bad90}
|
||||
category profile-after-change @mozilla.org/quitter-observer;1 @mozilla.org/quitter-observer;1
|
||||
component {c235a986-5ac1-4f28-ad73-825dae9bad90} components/QuitterObserver.js
|
||||
content quitter chrome/quitter/content/
|
||||
contract @mozilla.org/quitter-observer;1 {c235a986-5ac1-4f28-ad73-825dae9bad90}
|
||||
|
|
Загрузка…
Ссылка в новой задаче