Skip to content

Commit

Permalink
Ignore custom spellcheck dictionary words when using server-side spel…
Browse files Browse the repository at this point in the history
…lcheck

Chrome has been storing custom spellcheck dictionary words in the platform
spelling engine (Hunspell), which does not interact with the server-side
spellcheck. This has caused server-side spellcheck to not take into account
user's custom spellcheck dictionary. This CL moves handling of custom words from
platform spelling engine to spellchecker that uses both the platform spelling
engine and the server-side spellcheck.

BUG=169629


Review URL: https://chromiumcodereview.appspot.com/12303011

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@183497 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
rouslan@chromium.org committed Feb 20, 2013
1 parent 8925e0f commit 4ba74d9
Show file tree
Hide file tree
Showing 12 changed files with 139 additions and 137 deletions.
2 changes: 2 additions & 0 deletions chrome/chrome_renderer.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,8 @@
'renderer/security_filter_peer.h',
'renderer/spellchecker/cocoa_spelling_engine_mac.cc',
'renderer/spellchecker/cocoa_spelling_engine_mac.h',
'renderer/spellchecker/custom_dictionary_engine.cc',
'renderer/spellchecker/custom_dictionary_engine.h',
'renderer/spellchecker/hunspell_engine.cc',
'renderer/spellchecker/hunspell_engine.h',
'renderer/spellchecker/spellcheck_provider.cc',
Expand Down
9 changes: 1 addition & 8 deletions chrome/renderer/spellchecker/cocoa_spelling_engine_mac.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ SpellingEngine* CreateNativeSpellingEngine() {
return new CocoaSpellingEngine();
}

void CocoaSpellingEngine::Init(base::PlatformFile bdict_file,
const std::vector<std::string>&) {
void CocoaSpellingEngine::Init(base::PlatformFile bdict_file) {
DCHECK(bdict_file == base::kInvalidPlatformFileValue);
}

Expand Down Expand Up @@ -46,9 +45,3 @@ void CocoaSpellingEngine::FillSuggestionList(
RenderThread::Get()->Send(new SpellCheckHostMsg_FillSuggestionList(
wrong_word, optional_suggestions));
}

void CocoaSpellingEngine::OnCustomDictionaryChanged(
const std::vector<std::string>& words_added,
const std::vector<std::string>& words_removed) {
// OSX doesn't support the custom dictionary yet.
}
6 changes: 1 addition & 5 deletions chrome/renderer/spellchecker/cocoa_spelling_engine_mac.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,12 @@

class CocoaSpellingEngine : public SpellingEngine {
public:
virtual void Init(base::PlatformFile bdict_file,
const std::vector<std::string>& custom_words) OVERRIDE;
virtual void Init(base::PlatformFile bdict_file) OVERRIDE;
virtual bool InitializeIfNeeded() OVERRIDE;
virtual bool IsEnabled() OVERRIDE;
virtual bool CheckSpelling(const string16& word_to_check, int tag) OVERRIDE;
virtual void FillSuggestionList(const string16& wrong_word,
std::vector<string16>* optional_suggestions) OVERRIDE;
virtual void OnCustomDictionaryChanged(
const std::vector<std::string>& words_added,
const std::vector<std::string>& words_removed) OVERRIDE;
};

#endif // CHROME_RENDERER_SPELLCHECKER_NSSPELLCHECKER_ENGINE_H_
Expand Down
52 changes: 52 additions & 0 deletions chrome/renderer/spellchecker/custom_dictionary_engine.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/renderer/spellchecker/custom_dictionary_engine.h"

#include "base/logging.h"
#include "base/utf_string_conversions.h"

CustomDictionaryEngine::CustomDictionaryEngine() {
}

CustomDictionaryEngine::~CustomDictionaryEngine() {
}

void CustomDictionaryEngine::Init(
const std::vector<std::string>& custom_words) {
// SpellingMenuOberver calls UTF16ToUTF8(word) to convert words for storage,
// synchronization, and use in the custom dictionary engine. Since
// (UTF8ToUTF16(UTF16ToUTF8(word)) == word) holds, the engine does not need to
// normalize the strings.
for (std::vector<std::string>::const_iterator it = custom_words.begin();
it != custom_words.end();
++it) {
dictionary_.insert(UTF8ToUTF16(*it));
}
}

void CustomDictionaryEngine::OnCustomDictionaryChanged(
const std::vector<std::string>& words_added,
const std::vector<std::string>& words_removed) {
for (std::vector<std::string>::const_iterator it = words_added.begin();
it != words_added.end();
++it) {
dictionary_.insert(UTF8ToUTF16(*it));
}
for (std::vector<std::string>::const_iterator it = words_removed.begin();
it != words_removed.end();
++it) {
dictionary_.erase(UTF8ToUTF16(*it));
}
}

bool CustomDictionaryEngine::SpellCheckWord(
const char16* text,
int misspelling_start,
int misspelling_len) {
DCHECK(text);
return misspelling_start >= 0 &&
misspelling_len > 0 &&
dictionary_.count(string16(text, misspelling_start, misspelling_len)) > 0;
}
44 changes: 44 additions & 0 deletions chrome/renderer/spellchecker/custom_dictionary_engine.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_RENDERER_SPELLCHECKER_CUSTOM_DICTIONARY_ENGINE_H_
#define CHROME_RENDERER_SPELLCHECKER_CUSTOM_DICTIONARY_ENGINE_H_

#include <set>
#include <string>
#include <vector>

#include "base/string16.h"

// Custom spellcheck dictionary. Words in this dictionary are always correctly
// spelled. Words that are not in this dictionary may or may not be correctly
// spelled.
class CustomDictionaryEngine {
public:
CustomDictionaryEngine();
~CustomDictionaryEngine();

// Initialize the custom dictionary engine.
void Init(const std::vector<std::string>& words);

// Spellcheck |text|. Assumes that another spelling engine has set
// |misspelling_start| and |misspelling_len| to indicate a misspelling.
// Returns true if there are no misspellings, otherwise returns false.
bool SpellCheckWord(const char16* text,
int misspelling_start,
int misspelling_len);

// Update custom dictionary words.
void OnCustomDictionaryChanged(
const std::vector<std::string>& words_added,
const std::vector<std::string>& words_removed);

private:
// Correctly spelled words.
std::set<string16> dictionary_;

DISALLOW_COPY_AND_ASSIGN(CustomDictionaryEngine);
};

#endif // CHROME_RENDERER_SPELLCHECKER_CUSTOM_DICTIONARY_ENGINE_H_
64 changes: 1 addition & 63 deletions chrome/renderer/spellchecker/hunspell_engine.cc
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,11 @@ HunspellEngine::HunspellEngine()
HunspellEngine::~HunspellEngine() {
}

void HunspellEngine::Init(base::PlatformFile file,
const std::vector<std::string>& custom_words) {
void HunspellEngine::Init(base::PlatformFile file) {
initialized_ = true;
hunspell_.reset();
bdict_file_.reset();
file_ = file;

custom_words_.insert(custom_words_.end(),
custom_words.begin(), custom_words.end());

// Delay the actual initialization of hunspell until it is needed.
}

Expand All @@ -71,45 +66,13 @@ void HunspellEngine::InitializeHunspell() {
hunspell_.reset(
new Hunspell(bdict_file_->data(), bdict_file_->length()));

// Add custom words to Hunspell.
AddWordsToHunspell(custom_words_);

DHISTOGRAM_TIMES("Spellcheck.InitTime",
base::Histogram::DebugNow() - debug_start_time);
} else {
NOTREACHED() << "Could not mmap spellchecker dictionary.";
}
}

void HunspellEngine::AddWordsToHunspell(const std::vector<std::string>& words) {
std::string word;
for (chrome::spellcheck_common::WordList::const_iterator it = words.begin();
it != words.end();
++it) {
word = *it;
if (!word.empty() &&
word.length() <=
chrome::spellcheck_common::MAX_CUSTOM_DICTIONARY_WORD_BYTES) {
hunspell_->add(word.c_str());
}
}
}

void HunspellEngine::RemoveWordsFromHunspell(
const std::vector<std::string>& words) {
std::string word;
for (std::vector<std::string>::const_iterator it = words.begin();
it != words.end();
++it) {
word = *it;
if (!word.empty() &&
word.length() <=
chrome::spellcheck_common::MAX_CUSTOM_DICTIONARY_WORD_BYTES) {
hunspell_->remove(word.c_str());
}
}
}

bool HunspellEngine::CheckSpelling(const string16& word_to_check, int tag) {
// Assume all words that cannot be checked are valid. Since Chrome can't
// offer suggestions on them, either, there's no point in flagging them to
Expand Down Expand Up @@ -157,31 +120,6 @@ void HunspellEngine::FillSuggestionList(
free(suggestions);
}

void HunspellEngine::OnCustomDictionaryChanged(
const std::vector<std::string>& words_added,
const std::vector<std::string>& words_removed) {
if (!hunspell_.get()) {
// Save it for later---add it when hunspell is initialized.
custom_words_.insert(custom_words_.end(),
words_added.begin(),
words_added.end());
// Remove words.
std::vector<std::string> words_removed_copy(words_removed);
std::sort(words_removed_copy.begin(), words_removed_copy.end());
std::sort(custom_words_.begin(), custom_words_.end());
std::vector<std::string> updated_custom_words;
std::set_difference(custom_words_.begin(),
custom_words_.end(),
words_removed_copy.begin(),
words_removed_copy.end(),
std::back_inserter(updated_custom_words));
std::swap(custom_words_, updated_custom_words);
} else {
AddWordsToHunspell(words_added);
RemoveWordsFromHunspell(words_removed);
}
}

bool HunspellEngine::InitializeIfNeeded() {
if (!initialized_ && !dictionary_requested_) {
// RenderThread will not exist in test.
Expand Down
14 changes: 1 addition & 13 deletions chrome/renderer/spellchecker/hunspell_engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,37 +22,25 @@ class HunspellEngine : public SpellingEngine {
HunspellEngine();
virtual ~HunspellEngine();

virtual void Init(base::PlatformFile file,
const std::vector<std::string>& custom_words) OVERRIDE;
virtual void Init(base::PlatformFile file) OVERRIDE;

virtual bool InitializeIfNeeded() OVERRIDE;
virtual bool IsEnabled() OVERRIDE;
virtual bool CheckSpelling(const string16& word_to_check, int tag) OVERRIDE;
virtual void FillSuggestionList(const string16& wrong_word,
std::vector<string16>* optional_suggestions) OVERRIDE;
virtual void OnCustomDictionaryChanged(
const std::vector<std::string>& words_added,
const std::vector<std::string>& words_removed) OVERRIDE;

private:
// Initializes the Hunspell dictionary, or does nothing if |hunspell_| is
// non-null. This blocks.
void InitializeHunspell();

// Add the given custom words to |hunspell_|.
void AddWordsToHunspell(const std::vector<std::string>& words);

// Remove the given custom words from |hunspell_|.
void RemoveWordsFromHunspell(const std::vector<std::string>& words);

// We memory-map the BDict file.
scoped_ptr<file_util::MemoryMappedFile> bdict_file_;

// The hunspell dictionary in use.
scoped_ptr<Hunspell> hunspell_;

chrome::spellcheck_common::WordList custom_words_;

base::PlatformFile file_;

// This flags is true if we have been initialized.
Expand Down
49 changes: 27 additions & 22 deletions chrome/renderer/spellchecker/spellcheck.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include "base/bind.h"
#include "base/message_loop_proxy.h"
#include "base/utf_string_conversions.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/spellcheck_common.h"
#include "chrome/common/spellcheck_messages.h"
Expand Down Expand Up @@ -119,7 +120,7 @@ void SpellCheck::OnInit(IPC::PlatformFileForTransit bdict_file,
void SpellCheck::OnCustomDictionaryChanged(
const std::vector<std::string>& words_added,
const std::vector<std::string>& words_removed) {
spellcheck_.OnCustomDictionaryChanged(words_added, words_removed);
custom_dictionary_.OnCustomDictionaryChanged(words_added, words_removed);
}

void SpellCheck::OnEnableAutoSpellCorrect(bool enable) {
Expand All @@ -137,7 +138,8 @@ void SpellCheck::OnEnableSpellCheck(bool enable) {
void SpellCheck::Init(base::PlatformFile file,
const std::vector<std::string>& custom_words,
const std::string& language) {
spellcheck_.Init(file, custom_words, language);
spellcheck_.Init(file, language);
custom_dictionary_.Init(custom_words);
}

bool SpellCheck::SpellCheckWord(
Expand All @@ -159,17 +161,15 @@ bool SpellCheck::SpellCheckWord(
tag,
misspelling_start, misspelling_len,
optional_suggestions);

return true;
}

bool SpellCheck::SpellCheckParagraph(
const string16& text,
WebKit::WebVector<WebKit::WebTextCheckingResult>* results) {
WebVector<WebTextCheckingResult>* results) {
#if !defined(OS_MACOSX)
// Mac has its own spell checker, so this method will not be used.
DCHECK(results);
std::vector<WebKit::WebTextCheckingResult> textcheck_results;
std::vector<WebTextCheckingResult> textcheck_results;
size_t length = text.length();
size_t offset = 0;

Expand All @@ -191,12 +191,15 @@ bool SpellCheck::SpellCheckParagraph(
return true;
}

string16 replacement;
textcheck_results.push_back(WebKit::WebTextCheckingResult(
WebKit::WebTextCheckingTypeSpelling,
misspelling_start + offset,
misspelling_length,
replacement));
if (!custom_dictionary_.SpellCheckWord(
&text[offset], misspelling_start, misspelling_length)) {
string16 replacement;
textcheck_results.push_back(WebTextCheckingResult(
WebKit::WebTextCheckingTypeSpelling,
misspelling_start + offset,
misspelling_length,
replacement));
}
offset += misspelling_start + misspelling_length;
}
results->assign(textcheck_results);
Expand Down Expand Up @@ -300,7 +303,7 @@ void SpellCheck::PerformSpellCheck(SpellcheckRequest* param) {
if (!spellcheck_.IsEnabled()) {
param->completion()->didCancelCheckingText();
} else {
WebKit::WebVector<WebKit::WebTextCheckingResult> results;
WebVector<WebKit::WebTextCheckingResult> results;
SpellCheckParagraph(param->text(), &results);
param->completion()->didFinishCheckingText(results);
}
Expand All @@ -317,26 +320,28 @@ void SpellCheck::CreateTextCheckingResults(
// markers to them if our spellchecker tells they are correct words, i.e. they
// are probably contextually-misspelled words.
const char16* text = line_text.c_str();
WebVector<WebTextCheckingResult> list(spellcheck_results.size());
std::vector<WebTextCheckingResult> list;
for (size_t i = 0; i < spellcheck_results.size(); ++i) {
WebTextCheckingType type =
static_cast<WebTextCheckingType>(spellcheck_results[i].type);
int word_location = spellcheck_results[i].location;
int word_length = spellcheck_results[i].length;
int misspelling_start = 0;
int misspelling_length = 0;
if (type == WebKit::WebTextCheckingTypeSpelling &&
filter == USE_NATIVE_CHECKER) {
int misspelling_start = 0;
int misspelling_length = 0;
if (SpellCheckWord(text + word_location, word_length, 0,
&misspelling_start, &misspelling_length, NULL)) {
type = WebKit::WebTextCheckingTypeGrammar;
}
}
list[i] = WebKit::WebTextCheckingResult(type,
word_location + line_offset,
word_length,
spellcheck_results[i].replacement);
if (!custom_dictionary_.SpellCheckWord(text, word_location, word_length)) {
list.push_back(WebTextCheckingResult(
type,
word_location + line_offset,
word_length,
spellcheck_results[i].replacement));
}
}
textcheck_results->swap(list);
textcheck_results->assign(list);
}

Loading

0 comments on commit 4ba74d9

Please sign in to comment.