summaryrefslogtreecommitdiff
path: root/chromium/components/spellcheck/renderer
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/components/spellcheck/renderer')
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck.cc36
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck.h4
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_language.cc4
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_language.h4
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_provider.cc57
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_provider.h12
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_provider_test.cc52
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_provider_test.h26
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_provider_unittest.cc163
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_renderer_metrics.cc8
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_renderer_metrics.h4
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_worditerator.cc18
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_worditerator.h4
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_worditerator_unittest.cc72
-rw-r--r--chromium/components/spellcheck/renderer/spelling_engine.cc32
15 files changed, 339 insertions, 157 deletions
diff --git a/chromium/components/spellcheck/renderer/spellcheck.cc b/chromium/components/spellcheck/renderer/spellcheck.cc
index 53f87d5caaf..9a036faa65e 100644
--- a/chromium/components/spellcheck/renderer/spellcheck.cc
+++ b/chromium/components/spellcheck/renderer/spellcheck.cc
@@ -297,7 +297,7 @@ bool SpellCheck::SpellCheckWord(
suggestions_list.clear();
for (auto language = languages_.begin(); language != languages_.end();) {
-#if BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
+#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
if (!(*language)->IsEnabled()) {
// In the case of hybrid spell checking on Windows, languages that are
// handled on the browser side are marked as disabled on the renderer
@@ -306,7 +306,7 @@ bool SpellCheck::SpellCheckWord(
language++;
continue;
}
-#endif // BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
+#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
language_suggestions.clear();
SpellcheckLanguage::SpellcheckWordResult result =
@@ -363,18 +363,18 @@ bool SpellCheck::SpellCheckWord(
return false;
}
-#if BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
+#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
// If we're performing a hybrid spell check, we're only interested in
// knowing whether some Hunspell languages considered this text range as
// correctly spelled. If no misspellings were found, but the entire text was
// skipped, it means that no Hunspell language considered this text
// correct, so we should return false here.
- if (spellcheck::UseWinHybridSpellChecker() &&
+ if (spellcheck::UseBrowserSpellChecker() &&
EnabledLanguageCount() != LanguageCount() &&
agreed_skippable_len == text_length) {
return false;
}
-#endif // BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
+#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
}
NOTREACHED();
@@ -470,11 +470,11 @@ void SpellCheck::PerformSpellCheck(SpellcheckRequest* param) {
WebVector<blink::WebTextCheckingResult> results;
SpellCheckParagraph(param->text(), &results);
param->completion()->DidFinishCheckingText(results);
-#if BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
+#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
spellcheck_renderer_metrics::RecordSpellcheckDuration(
base::TimeTicks::Now() - param->start_ticks(),
/*used_hunspell=*/true, /*used_native=*/false);
-#endif // BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
+#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
}
}
#endif
@@ -501,6 +501,15 @@ void SpellCheck::CreateTextCheckingResults(
spellcheck_result.replacements;
SpellCheckResult::Decoration decoration = spellcheck_result.decoration;
+#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+ // Ignore words that are in a script not supported by any of the enabled
+ // spellcheck languages.
+ if (spellcheck::UseBrowserSpellChecker() &&
+ !IsWordInSupportedScript(misspelled_word)) {
+ continue;
+ }
+#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+
// Ignore words in custom dictionary.
if (custom_dictionary_.SpellCheckWord(misspelled_word, 0,
misspelled_word.length())) {
@@ -530,9 +539,9 @@ void SpellCheck::CreateTextCheckingResults(
decoration = SpellCheckResult::GRAMMAR;
}
}
-#if BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
+#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
else if (filter == USE_HUNSPELL_FOR_HYBRID_CHECK &&
- spellcheck::UseWinHybridSpellChecker() &&
+ spellcheck::UseBrowserSpellChecker() &&
EnabledLanguageCount() > 0) {
// Remove the suggestions that were generated by the native spell checker,
// otherwise Blink will cache them without asking for the suggestions
@@ -562,7 +571,7 @@ void SpellCheck::CreateTextCheckingResults(
}
}
}
-#endif // BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
+#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
results.push_back(
WebTextCheckingResult(static_cast<WebTextDecorationType>(decoration),
@@ -607,3 +616,10 @@ void SpellCheck::NotifyDictionaryObservers(
observer.OnDictionaryUpdated(words_added);
}
}
+
+bool SpellCheck::IsWordInSupportedScript(const base::string16& word) const {
+ return std::find_if(languages_.begin(), languages_.end(),
+ [word](const auto& language) {
+ return language->IsTextInSameScript(word);
+ }) != languages_.end();
+}
diff --git a/chromium/components/spellcheck/renderer/spellcheck.h b/chromium/components/spellcheck/renderer/spellcheck.h
index 2fc497918cc..7327f78e750 100644
--- a/chromium/components/spellcheck/renderer/spellcheck.h
+++ b/chromium/components/spellcheck/renderer/spellcheck.h
@@ -192,6 +192,10 @@ class SpellCheck : public base::SupportsWeakPtr<SpellCheck>,
void NotifyDictionaryObservers(
const blink::WebVector<blink::WebString>& words_added);
+ // Returns whether a word is in the script of one of the enabled spellcheck
+ // languages.
+ bool IsWordInSupportedScript(const base::string16& word) const;
+
#if BUILDFLAG(USE_RENDERER_SPELLCHECKER)
// Posts delayed spellcheck task and clear it if any.
// Takes ownership of |request|.
diff --git a/chromium/components/spellcheck/renderer/spellcheck_language.cc b/chromium/components/spellcheck/renderer/spellcheck_language.cc
index 391e36a9481..32ff29257ad 100644
--- a/chromium/components/spellcheck/renderer/spellcheck_language.cc
+++ b/chromium/components/spellcheck/renderer/spellcheck_language.cc
@@ -148,3 +148,7 @@ bool SpellcheckLanguage::IsEnabled() {
DCHECK(platform_spelling_engine_);
return platform_spelling_engine_->IsEnabled();
}
+
+bool SpellcheckLanguage::IsTextInSameScript(const base::string16& text) const {
+ return character_attributes_.IsTextInSameScript(text);
+}
diff --git a/chromium/components/spellcheck/renderer/spellcheck_language.h b/chromium/components/spellcheck/renderer/spellcheck_language.h
index ed909b10bc0..6e35078a95e 100644
--- a/chromium/components/spellcheck/renderer/spellcheck_language.h
+++ b/chromium/components/spellcheck/renderer/spellcheck_language.h
@@ -75,6 +75,10 @@ class SpellcheckLanguage {
// Return true if the underlying spellcheck engine is enabled.
bool IsEnabled();
+ // Returns true if all the characters in a text string are in the script
+ // associated with this spellcheck language.
+ bool IsTextInSameScript(const base::string16& text) const;
+
private:
friend class SpellCheckTest;
friend class FakeSpellCheck;
diff --git a/chromium/components/spellcheck/renderer/spellcheck_provider.cc b/chromium/components/spellcheck/renderer/spellcheck_provider.cc
index 58e2434a7ce..76f4452ab02 100644
--- a/chromium/components/spellcheck/renderer/spellcheck_provider.cc
+++ b/chromium/components/spellcheck/renderer/spellcheck_provider.cc
@@ -134,8 +134,10 @@ void SpellCheckProvider::RequestTextChecking(
last_results_.Assign(blink::WebVector<blink::WebTextCheckingResult>());
last_identifier_ = text_check_completions_.Add(std::move(completion));
-#if BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
- if (spellcheck::UseWinHybridSpellChecker()) {
+#if BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+ if (spellcheck::UseBrowserSpellChecker()) {
+#if defined(OS_WIN)
+ // Determine whether a hybrid check is needed.
bool use_hunspell = spellcheck_->EnabledLanguageCount() > 0;
bool use_native =
spellcheck_->EnabledLanguageCount() != spellcheck_->LanguageCount();
@@ -145,33 +147,26 @@ void SpellCheckProvider::RequestTextChecking(
return;
}
- if (use_native) {
- // Some languages can be handled by the native spell checker. Use the
- // regular browser spell check code path. If hybrid spell check is
- // required (i.e. some locales must be checked by Hunspell), misspellings
- // from the native spell checker will be double-checked with Hunspell in
- // the |OnRespondTextCheck| callback.
- hybrid_requests_info_[last_identifier_] = {/*used_hunspell=*/use_hunspell,
- /*used_native=*/use_native,
- base::TimeTicks::Now()};
- GetSpellCheckHost().RequestTextCheck(
- text, routing_id(),
- base::BindOnce(&SpellCheckProvider::OnRespondTextCheck,
- weak_factory_.GetWeakPtr(), last_identifier_, text));
- } else {
+ if (!use_native) {
// No language can be handled by the native spell checker. Use the regular
// Hunspell code path.
GetSpellCheckHost().CallSpellingService(
text,
base::BindOnce(&SpellCheckProvider::OnRespondSpellingService,
weak_factory_.GetWeakPtr(), last_identifier_, text));
+ return;
}
- return;
- }
-#endif // BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
-#if BUILDFLAG(USE_BROWSER_SPELLCHECKER)
- if (spellcheck::UseBrowserSpellChecker()) {
+ // Some languages can be handled by the native spell checker. Use the
+ // regular browser spell check code path. If hybrid spell check is
+ // required (i.e. some locales must be checked by Hunspell), misspellings
+ // from the native spell checker will be double-checked with Hunspell in
+ // the |OnRespondTextCheck| callback.
+ hybrid_requests_info_[last_identifier_] = {/*used_hunspell=*/use_hunspell,
+ /*used_native=*/use_native,
+ base::TimeTicks::Now()};
+#endif // defined(OS_WIN)
+
// Text check (unified request for grammar and spell check) is only
// available for browser process, so we ask the system spellchecker
// over mojo or return an empty result if the checker is not available.
@@ -221,16 +216,16 @@ void SpellCheckProvider::CheckSpelling(
const int kWordStart = 0;
if (optional_suggestions) {
-#if BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
+#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
base::TimeTicks suggestions_start = base::TimeTicks::Now();
-#endif // BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
+#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
spellcheck::PerLanguageSuggestions per_language_suggestions;
spellcheck_->SpellCheckWord(word.c_str(), kWordStart, word.size(),
routing_id(), &offset, &length,
&per_language_suggestions);
-#if BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
- if (spellcheck::UseWinHybridSpellChecker() &&
+#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+ if (spellcheck::UseBrowserSpellChecker() &&
spellcheck_->EnabledLanguageCount() < spellcheck_->LanguageCount()) {
// Also fetch suggestions from the browser process (native spellchecker).
// This is a synchronous Mojo call, because this method must return
@@ -249,7 +244,7 @@ void SpellCheckProvider::CheckSpelling(
spellcheck_renderer_metrics::RecordHunspellSuggestionDuration(
base::TimeTicks::Now() - suggestions_start);
}
-#endif // BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
+#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
std::vector<base::string16> suggestions;
spellcheck::FillSuggestions(per_language_suggestions, &suggestions);
@@ -342,29 +337,29 @@ void SpellCheckProvider::OnRespondTextCheck(
SpellCheck::ResultFilter result_filter = SpellCheck::DO_NOT_MODIFY;
-#if BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
+#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
const auto& request_info = hybrid_requests_info_.find(identifier);
- if (spellcheck::UseWinHybridSpellChecker() &&
+ if (spellcheck::UseBrowserSpellChecker() &&
request_info != hybrid_requests_info_.end() &&
request_info->second.used_hunspell && request_info->second.used_native) {
// Not all locales could be checked by the native spell checker. Verify each
// mistake against Hunspell in the locales that weren't checked.
result_filter = SpellCheck::USE_HUNSPELL_FOR_HYBRID_CHECK;
}
-#endif // BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
+#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
spellcheck_->CreateTextCheckingResults(result_filter,
/*line_offset=*/0, line, results,
&textcheck_results);
-#if BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
+#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
if (request_info != hybrid_requests_info_.end()) {
spellcheck_renderer_metrics::RecordSpellcheckDuration(
base::TimeTicks::Now() - request_info->second.request_start_ticks,
request_info->second.used_hunspell, request_info->second.used_native);
hybrid_requests_info_.erase(request_info);
}
-#endif // BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
+#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
completion->DidFinishCheckingText(textcheck_results);
diff --git a/chromium/components/spellcheck/renderer/spellcheck_provider.h b/chromium/components/spellcheck/renderer/spellcheck_provider.h
index 8e852264682..43e6dd2a46b 100644
--- a/chromium/components/spellcheck/renderer/spellcheck_provider.h
+++ b/chromium/components/spellcheck/renderer/spellcheck_provider.h
@@ -18,9 +18,9 @@
#include "mojo/public/cpp/bindings/remote.h"
#include "third_party/blink/public/web/web_text_check_client.h"
-#if BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
+#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
#include <unordered_map>
-#endif // BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
+#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
class SpellCheck;
struct SpellCheckResult;
@@ -46,14 +46,14 @@ class SpellCheckProvider : public content::RenderFrameObserver,
using WebTextCheckCompletions =
base::IDMap<std::unique_ptr<blink::WebTextCheckingCompletion>>;
-#if BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
+#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
// A struct to hold information related to hybrid spell check requests.
struct HybridSpellCheckRequestInfo {
bool used_hunspell;
bool used_native;
base::TimeTicks request_start_ticks;
};
-#endif // BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
+#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
SpellCheckProvider(
content::RenderFrame* render_frame,
@@ -155,9 +155,9 @@ class SpellCheckProvider : public content::RenderFrameObserver,
// Dictionary updated observer.
std::unique_ptr<DictionaryUpdateObserverImpl> dictionary_update_observer_;
-#if BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
+#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
std::unordered_map<int, HybridSpellCheckRequestInfo> hybrid_requests_info_;
-#endif // BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
+#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
base::WeakPtrFactory<SpellCheckProvider> weak_factory_{this};
diff --git a/chromium/components/spellcheck/renderer/spellcheck_provider_test.cc b/chromium/components/spellcheck/renderer/spellcheck_provider_test.cc
index c2d6414b1ba..9683a995a80 100644
--- a/chromium/components/spellcheck/renderer/spellcheck_provider_test.cc
+++ b/chromium/components/spellcheck/renderer/spellcheck_provider_test.cc
@@ -16,13 +16,11 @@
#include "components/spellcheck/renderer/spellcheck_language.h"
#include "components/spellcheck/spellcheck_buildflags.h"
-#if BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
+#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/path_service.h"
-#endif // BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
-#if BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
namespace {
base::FilePath GetHunspellDirectory() {
base::FilePath hunspell_directory;
@@ -34,7 +32,7 @@ base::FilePath GetHunspellDirectory() {
return hunspell_directory;
}
} // namespace
-#endif // BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
+#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
FakeTextCheckingResult::FakeTextCheckingResult() = default;
FakeTextCheckingResult::~FakeTextCheckingResult() = default;
@@ -67,26 +65,31 @@ void FakeSpellCheck::SetFakeLanguageCounts(size_t language_count,
enabled_language_count_ = enabled_count;
}
-#if BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
-void FakeSpellCheck::InitializeRendererSpellCheckForLocale(
- const std::string& language) {
- base::FilePath hunspell_directory = GetHunspellDirectory();
- EXPECT_FALSE(hunspell_directory.empty());
- base::FilePath hunspell_file_path =
- spellcheck::GetVersionedFileName(language, hunspell_directory);
- base::File file(hunspell_file_path,
- base::File::FLAG_OPEN | base::File::FLAG_READ);
- EXPECT_TRUE(file.IsValid()) << hunspell_file_path << " is not valid"
- << file.ErrorToString(file.GetLastFileError());
+#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+void FakeSpellCheck::InitializeSpellCheckForLocale(const std::string& language,
+ bool use_hunspell) {
+ // Non-Hunspell case is passed invalid file to SpellcheckLanguage::Init.
+ base::File file;
+
+ if (use_hunspell) {
+ base::FilePath hunspell_directory = GetHunspellDirectory();
+ EXPECT_FALSE(hunspell_directory.empty());
+ base::FilePath hunspell_file_path =
+ spellcheck::GetVersionedFileName(language, hunspell_directory);
+ file.Initialize(hunspell_file_path,
+ base::File::FLAG_OPEN | base::File::FLAG_READ);
+ EXPECT_TRUE(file.IsValid()) << hunspell_file_path << " is not valid"
+ << file.ErrorToString(file.GetLastFileError());
+ }
- // Add the SpellcheckLanguage manually to force the use of Hunspell.
+ // Add the SpellcheckLanguage manually to the SpellCheck object.
SpellCheck::languages_.push_back(
std::make_unique<SpellcheckLanguage>(embedder_provider_));
- SpellCheck::languages_.front()->platform_spelling_engine_ =
+ SpellCheck::languages_.back()->platform_spelling_engine_ =
std::make_unique<HunspellEngine>(embedder_provider_);
- SpellCheck::languages_.front()->Init(std::move(file), language);
+ SpellCheck::languages_.back()->Init(std::move(file), language);
}
-#endif // BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
+#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
size_t FakeSpellCheck::LanguageCount() {
return use_fake_counts_ ? language_count_ : SpellCheck::LanguageCount();
@@ -180,15 +183,16 @@ void TestingSpellCheckProvider::FillSuggestionList(const base::string16&,
FillSuggestionListCallback) {
NOTREACHED();
}
-#endif // BUILDFLAG(USE_BROWSER_SPELLCHECKER)
-#if BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
+#if defined(OS_WIN)
void TestingSpellCheckProvider::GetPerLanguageSuggestions(
const base::string16& word,
GetPerLanguageSuggestionsCallback callback) {
NOTREACHED();
}
-#endif // BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
+#endif // defined(OS_WIN)
+
+#endif // BUILDFLAG(USE_BROWSER_SPELLCHECKER)
#if defined(OS_ANDROID)
void TestingSpellCheckProvider::DisconnectSessionBridge() {
@@ -209,7 +213,7 @@ bool TestingSpellCheckProvider::SatisfyRequestFromCache(
return SpellCheckProvider::SatisfyRequestFromCache(text, completion);
}
-#if BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
+#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
int TestingSpellCheckProvider::AddCompletionForTest(
std::unique_ptr<FakeTextCheckingCompletion> completion,
SpellCheckProvider::HybridSpellCheckRequestInfo request_info) {
@@ -226,7 +230,7 @@ void TestingSpellCheckProvider::OnRespondTextCheck(
SpellCheckProvider::OnRespondTextCheck(identifier, line, results);
base::RunLoop().RunUntilIdle();
}
-#endif // BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
+#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
SpellCheckProviderTest::SpellCheckProviderTest()
: provider_(&embedder_provider_) {}
diff --git a/chromium/components/spellcheck/renderer/spellcheck_provider_test.h b/chromium/components/spellcheck/renderer/spellcheck_provider_test.h
index 3ed4bdf61cf..7d5516639d1 100644
--- a/chromium/components/spellcheck/renderer/spellcheck_provider_test.h
+++ b/chromium/components/spellcheck/renderer/spellcheck_provider_test.h
@@ -53,10 +53,11 @@ class FakeSpellCheck : public SpellCheck {
// Test-only method to set the fake language counts
void SetFakeLanguageCounts(size_t language_count, size_t enabled_count);
-#if BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
- // Test-only method to initialize Hunspell for the given locale.
- void InitializeRendererSpellCheckForLocale(const std::string& language);
-#endif // BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
+#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+ // Test-only method to initialize SpellCheck object for the given locale.
+ void InitializeSpellCheckForLocale(const std::string& language,
+ bool use_hunspell);
+#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
// Returns the current number of spell check languages.
size_t LanguageCount() override;
@@ -91,7 +92,7 @@ class TestingSpellCheckProvider : public SpellCheckProvider,
bool SatisfyRequestFromCache(const base::string16& text,
blink::WebTextCheckingCompletion* completion);
-#if BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
+#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
int AddCompletionForTest(
std::unique_ptr<FakeTextCheckingCompletion> completion,
SpellCheckProvider::HybridSpellCheckRequestInfo request_info);
@@ -99,7 +100,7 @@ class TestingSpellCheckProvider : public SpellCheckProvider,
void OnRespondTextCheck(int identifier,
const base::string16& line,
const std::vector<SpellCheckResult>& results);
-#endif // BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
+#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
#if BUILDFLAG(USE_RENDERER_SPELLCHECKER)
void ResetResult();
@@ -109,14 +110,10 @@ class TestingSpellCheckProvider : public SpellCheckProvider,
size_t spelling_service_call_count_ = 0;
#endif // BUILDFLAG(USE_RENDERER_SPELLCHECKER)
-#if BUILDFLAG(USE_BROWSER_SPELLCHECKER) || \
- BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
+#if BUILDFLAG(USE_BROWSER_SPELLCHECKER)
using RequestTextCheckParams =
std::pair<base::string16, RequestTextCheckCallback>;
-#endif // BUILDFLAG(USE_BROWSER_SPELLCHECKER) ||
- // BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
-#if BUILDFLAG(USE_BROWSER_SPELLCHECKER)
// Variables logging RequestTextCheck() mojo calls.
std::vector<RequestTextCheckParams> text_check_requests_;
#endif // BUILDFLAG(USE_BROWSER_SPELLCHECKER)
@@ -147,13 +144,14 @@ class TestingSpellCheckProvider : public SpellCheckProvider,
CheckSpellingCallback) override;
void FillSuggestionList(const base::string16&,
FillSuggestionListCallback) override;
-#endif
-#if BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
+#if defined(OS_WIN)
void GetPerLanguageSuggestions(
const base::string16& word,
GetPerLanguageSuggestionsCallback callback) override;
-#endif // BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
+#endif // defined(OS_WIN)
+
+#endif
#if defined(OS_ANDROID)
void DisconnectSessionBridge() override;
diff --git a/chromium/components/spellcheck/renderer/spellcheck_provider_unittest.cc b/chromium/components/spellcheck/renderer/spellcheck_provider_unittest.cc
index cdc3995a487..8629702ac57 100644
--- a/chromium/components/spellcheck/renderer/spellcheck_provider_unittest.cc
+++ b/chromium/components/spellcheck/renderer/spellcheck_provider_unittest.cc
@@ -18,7 +18,7 @@
namespace {
-#if BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
+#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
struct HybridSpellCheckTestCase {
size_t language_count;
size_t enabled_language_count;
@@ -27,13 +27,23 @@ struct HybridSpellCheckTestCase {
};
struct CombineSpellCheckResultsTestCase {
+ std::string browser_locale;
std::string renderer_locale;
const wchar_t* text;
std::vector<SpellCheckResult> browser_results;
bool use_spelling_service;
blink::WebVector<blink::WebTextCheckingResult> expected_results;
};
-#endif // BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
+
+std::ostream& operator<<(std::ostream& out,
+ const CombineSpellCheckResultsTestCase& test_case) {
+ out << "browser_locale=" << test_case.browser_locale
+ << ", renderer_locale=" << test_case.renderer_locale << ", text=\""
+ << test_case.text
+ << "\", use_spelling_service=" << test_case.use_spelling_service;
+ return out;
+}
+#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
class SpellCheckProviderCacheTest : public SpellCheckProviderTest {
protected:
@@ -47,7 +57,7 @@ class SpellCheckProviderCacheTest : public SpellCheckProviderTest {
}
};
-#if BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
+#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
// Test fixture for testing hybrid check cases.
class HybridSpellCheckTest
: public testing::TestWithParam<HybridSpellCheckTestCase> {
@@ -74,7 +84,7 @@ class CombineSpellCheckResultsTest
spellcheck::EmptyLocalInterfaceProvider embedder_provider_;
TestingSpellCheckProvider provider_;
};
-#endif // BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
+#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
TEST_F(SpellCheckProviderCacheTest, SubstringWithoutMisspellings) {
FakeTextCheckingResult result;
@@ -128,7 +138,7 @@ TEST_F(SpellCheckProviderCacheTest, ResetCacheOnCustomDictionaryUpdate) {
EXPECT_EQ(result.completion_count_, 0U);
}
-#if BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
+#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
// Tests that the SpellCheckProvider does not call into the native spell checker
// on Windows when the native spell checker flags are disabled.
TEST_F(SpellCheckProviderTest, ShouldNotUseBrowserSpellCheck) {
@@ -146,29 +156,6 @@ TEST_F(SpellCheckProviderTest, ShouldNotUseBrowserSpellCheck) {
EXPECT_EQ(completion.cancellation_count_, 0U);
}
-// Tests that the SpellCheckProvider calls into the native spell checker when
-// the browser spell checker flag is enabled, but the hybrid spell checker flag
-// isn't.
-TEST_F(SpellCheckProviderTest, ShouldUseBrowserSpellCheck) {
- if (!spellcheck::WindowsVersionSupportsSpellchecker()) {
- return;
- }
-
- base::test::ScopedFeatureList local_features;
- local_features.InitWithFeatures({spellcheck::kWinUseBrowserSpellChecker},
- {spellcheck::kWinUseHybridSpellChecker});
-
- FakeTextCheckingResult completion;
- base::string16 text = base::ASCIIToUTF16("This is a test");
- provider_.RequestTextChecking(
- text, std::make_unique<FakeTextCheckingCompletion>(&completion));
-
- EXPECT_EQ(provider_.spelling_service_call_count_, 0U);
- EXPECT_EQ(provider_.text_check_requests_.size(), 1U);
- EXPECT_EQ(completion.completion_count_, 0U);
- EXPECT_EQ(completion.cancellation_count_, 0U);
-}
-
// Tests that the SpellCheckProvider calls into the native spell checker only
// when needed.
INSTANTIATE_TEST_SUITE_P(
@@ -197,10 +184,7 @@ TEST_P(HybridSpellCheckTest, ShouldUseBrowserSpellCheckOnlyWhenNeeded) {
const auto& test_case = GetParam();
base::test::ScopedFeatureList local_features;
- local_features.InitWithFeatures(
- /*enabled_features=*/{spellcheck::kWinUseBrowserSpellChecker,
- spellcheck::kWinUseHybridSpellChecker},
- /*disabled_features=*/{});
+ local_features.InitAndEnableFeature(spellcheck::kWinUseBrowserSpellChecker);
FakeTextCheckingResult completion;
provider_.spellcheck()->SetFakeLanguageCounts(
@@ -225,7 +209,8 @@ INSTANTIATE_TEST_SUITE_P(
CombineSpellCheckResultsTest,
testing::Values(
// Browser-only check, no browser results
- CombineSpellCheckResultsTestCase{"",
+ CombineSpellCheckResultsTestCase{"en-US",
+ "",
L"This has no misspellings",
{},
false,
@@ -233,6 +218,7 @@ INSTANTIATE_TEST_SUITE_P(
// Browser-only check, no spelling service, browser results
CombineSpellCheckResultsTestCase{
+ "en-US",
"",
L"Tihs has soem misspellings",
{SpellCheckResult(SpellCheckResult::SPELLING,
@@ -256,8 +242,56 @@ INSTANTIATE_TEST_SUITE_P(
9,
4)})},
+ // Browser-only check, no spelling service, browser results, some words
+ // in character sets with no dictionaries enabled.
+ CombineSpellCheckResultsTestCase{
+ "en-US",
+ "",
+ L"Tihs has soem \x3053\x3093\x306B\x3061\x306F \x4F60\x597D "
+ L"\xC548\xB155\xD558\xC138\xC694 "
+ L"\x0930\x093E\x091C\x0927\x093E\x0928 words in different "
+ L"character sets "
+ L"(Japanese, Chinese, Korean, Hindi)",
+ {SpellCheckResult(SpellCheckResult::SPELLING,
+ 0,
+ 4,
+ {base::ASCIIToUTF16("foo")}),
+ SpellCheckResult(SpellCheckResult::SPELLING,
+ 9,
+ 4,
+ {base::ASCIIToUTF16("foo")}),
+ SpellCheckResult(SpellCheckResult::SPELLING,
+ 14,
+ 5,
+ {base::ASCIIToUTF16("foo")}),
+ SpellCheckResult(SpellCheckResult::SPELLING,
+ 20,
+ 2,
+ {base::ASCIIToUTF16("foo")}),
+ SpellCheckResult(SpellCheckResult::SPELLING,
+ 23,
+ 5,
+ {base::ASCIIToUTF16("foo")}),
+ SpellCheckResult(SpellCheckResult::SPELLING,
+ 29,
+ 6,
+ {base::ASCIIToUTF16("foo")})},
+ false,
+ blink::WebVector<blink::WebTextCheckingResult>(
+ {blink::WebTextCheckingResult(
+ blink::WebTextDecorationType::
+ kWebTextDecorationTypeSpelling,
+ 0,
+ 4),
+ blink::WebTextCheckingResult(
+ blink::WebTextDecorationType::
+ kWebTextDecorationTypeSpelling,
+ 9,
+ 4)})},
+
// Browser-only check, spelling service, spelling-only browser results
CombineSpellCheckResultsTestCase{
+ "en-US",
"",
L"Tihs has soem misspellings",
{SpellCheckResult(SpellCheckResult::SPELLING,
@@ -284,6 +318,7 @@ INSTANTIATE_TEST_SUITE_P(
// Browser-only check, spelling service, spelling and grammar browser
// results
CombineSpellCheckResultsTestCase{
+ "en-US",
"",
L"Tihs has soem misspellings",
{SpellCheckResult(SpellCheckResult::SPELLING,
@@ -308,6 +343,7 @@ INSTANTIATE_TEST_SUITE_P(
// Hybrid check, no browser results
CombineSpellCheckResultsTestCase{"en-US",
+ "en-US",
L"This has no misspellings",
{},
false,
@@ -317,6 +353,7 @@ INSTANTIATE_TEST_SUITE_P(
// with Hunspell results
CombineSpellCheckResultsTestCase{
"en-US",
+ "en-US",
L"Tihs has soem misspellings",
{SpellCheckResult(SpellCheckResult::SPELLING,
0,
@@ -343,6 +380,7 @@ INSTANTIATE_TEST_SUITE_P(
// coincide with Hunspell results
CombineSpellCheckResultsTestCase{
"en-US",
+ "en-US",
L"Tihs has soem misspellings",
{
SpellCheckResult(SpellCheckResult::SPELLING,
@@ -379,6 +417,7 @@ INSTANTIATE_TEST_SUITE_P(
// coincide with Hunspell results
CombineSpellCheckResultsTestCase{
"en-US",
+ "en-US",
L"Tihs has soem misspellings",
{SpellCheckResult(SpellCheckResult::SPELLING,
5,
@@ -392,10 +431,40 @@ INSTANTIATE_TEST_SUITE_P(
blink::WebVector<blink::WebTextCheckingResult>()},
// Hybrid check, no spelling service, browser results with some that
- // are skipped by Hunspell because of character set mismatch
+ // that are in character set that does not have dictionary support (so
+ // (are considered spelled correctly)
CombineSpellCheckResultsTestCase{
"en-US",
- L"Tihs word is misspelled in Russian: "
+ "fr",
+ L"Tihs mot is misspelled in Russian: "
+ L"\x043C\x0438\x0440\x0432\x043E\x0439",
+ {SpellCheckResult(SpellCheckResult::SPELLING,
+ 0,
+ 4,
+ {base::ASCIIToUTF16("foo")}),
+ SpellCheckResult(SpellCheckResult::SPELLING,
+ 5,
+ 3,
+ {base::ASCIIToUTF16("foo")}),
+ SpellCheckResult(SpellCheckResult::SPELLING,
+ 35,
+ 6,
+ {base::ASCIIToUTF16("foo")})},
+ false,
+ blink::WebVector<blink::WebTextCheckingResult>(
+ std::vector<blink::WebTextCheckingResult>(
+ {blink::WebTextCheckingResult(
+ blink::WebTextDecorationType::
+ kWebTextDecorationTypeSpelling,
+ 0,
+ 4)}))},
+
+ // Hybrid check, no spelling service, text with some words in a
+ // character set that only has a Hunspell dictionary enabled.
+ CombineSpellCheckResultsTestCase{
+ "en-US",
+ "ru",
+ L"Tihs \x0432\x0441\x0435\x0445 is misspelled in Russian: "
L"\x043C\x0438\x0440\x0432\x043E\x0439",
{SpellCheckResult(SpellCheckResult::SPELLING,
0,
@@ -426,6 +495,7 @@ INSTANTIATE_TEST_SUITE_P(
// that all coincide with Hunspell results
CombineSpellCheckResultsTestCase{
"en-US",
+ "en-US",
L"Tihs has soem misspellings",
{SpellCheckResult(SpellCheckResult::SPELLING,
0,
@@ -452,6 +522,7 @@ INSTANTIATE_TEST_SUITE_P(
// locales
CombineSpellCheckResultsTestCase{
"en-US",
+ "en-US",
L"This has soem misspellings",
{SpellCheckResult(SpellCheckResult::SPELLING,
0,
@@ -480,16 +551,18 @@ TEST_P(CombineSpellCheckResultsTest, ShouldCorrectlyCombineHybridResults) {
const auto& test_case = GetParam();
base::test::ScopedFeatureList local_features;
- local_features.InitWithFeatures(
- /*enabled_features=*/{spellcheck::kWinUseBrowserSpellChecker,
- spellcheck::kWinUseHybridSpellChecker},
- /*disabled_features=*/{});
- bool has_renderer_check = !test_case.renderer_locale.empty();
+ local_features.InitAndEnableFeature(spellcheck::kWinUseBrowserSpellChecker);
+ const bool has_browser_check = !test_case.browser_locale.empty();
+ const bool has_renderer_check = !test_case.renderer_locale.empty();
+
+ if (has_browser_check) {
+ provider_.spellcheck()->InitializeSpellCheckForLocale(
+ test_case.browser_locale, /*use_hunspell*/ false);
+ }
if (has_renderer_check) {
- provider_.spellcheck()->InitializeRendererSpellCheckForLocale(
- test_case.renderer_locale);
- provider_.spellcheck()->SetFakeLanguageCounts(2u, 1u);
+ provider_.spellcheck()->InitializeSpellCheckForLocale(
+ test_case.renderer_locale, /*use_hunspell*/ true);
}
if (test_case.use_spelling_service) {
@@ -501,7 +574,7 @@ TEST_P(CombineSpellCheckResultsTest, ShouldCorrectlyCombineHybridResults) {
FakeTextCheckingResult completion;
SpellCheckProvider::HybridSpellCheckRequestInfo request_info = {
/*used_hunspell=*/has_renderer_check,
- /*used_native=*/true, base::TimeTicks::Now()};
+ /*used_native=*/has_browser_check, base::TimeTicks::Now()};
int check_id = provider_.AddCompletionForTest(
std::make_unique<FakeTextCheckingCompletion>(&completion), request_info);
@@ -536,6 +609,6 @@ TEST_P(CombineSpellCheckResultsTest, ShouldCorrectlyCombineHybridResults) {
}
}
}
-#endif // BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
+#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
} // namespace
diff --git a/chromium/components/spellcheck/renderer/spellcheck_renderer_metrics.cc b/chromium/components/spellcheck/renderer/spellcheck_renderer_metrics.cc
index bae7b795136..44d29923868 100644
--- a/chromium/components/spellcheck/renderer/spellcheck_renderer_metrics.cc
+++ b/chromium/components/spellcheck/renderer/spellcheck_renderer_metrics.cc
@@ -12,7 +12,7 @@
#include "build/build_config.h"
#include "components/spellcheck/spellcheck_buildflags.h"
-#if BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
+#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
namespace {
// Records the duration of a spell check request. This variation is for when
@@ -37,7 +37,7 @@ void RecordNativeSpellcheckDuration(base::TimeDelta duration) {
}
} // anonymous namespace
-#endif // BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
+#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
namespace spellcheck_renderer_metrics {
@@ -53,7 +53,7 @@ void RecordCheckedTextLengthWithSuggestions(int length) {
UMA_HISTOGRAM_COUNTS_1M("SpellCheck.api.check.suggestions", length);
}
-#if BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
+#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
void RecordHunspellSuggestionDuration(base::TimeDelta duration) {
UMA_HISTOGRAM_TIMES(
"Spellcheck.Windows.SuggestionGatheringDuration.HunspellOnly", duration);
@@ -75,7 +75,7 @@ void RecordSpellcheckDuration(base::TimeDelta duration,
RecordNativeSpellcheckDuration(duration);
}
}
-#endif // BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
+#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
} // namespace spellcheck_renderer_metrics
diff --git a/chromium/components/spellcheck/renderer/spellcheck_renderer_metrics.h b/chromium/components/spellcheck/renderer/spellcheck_renderer_metrics.h
index 9ad71c4f923..a052bf7ff0b 100644
--- a/chromium/components/spellcheck/renderer/spellcheck_renderer_metrics.h
+++ b/chromium/components/spellcheck/renderer/spellcheck_renderer_metrics.h
@@ -25,7 +25,7 @@ void RecordCheckedTextLengthNoSuggestions(int length);
// requested.
void RecordCheckedTextLengthWithSuggestions(int length);
-#if BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
+#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
// Records the duration of gathering spelling suggestions. This variation is for
// when spell check is performed only by Hunspell.
void RecordHunspellSuggestionDuration(base::TimeDelta duration);
@@ -41,7 +41,7 @@ void RecordHybridSuggestionDuration(base::TimeDelta duration);
void RecordSpellcheckDuration(base::TimeDelta duration,
bool used_hunspell,
bool used_native);
-#endif // BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
+#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
} // namespace spellcheck_renderer_metrics
diff --git a/chromium/components/spellcheck/renderer/spellcheck_worditerator.cc b/chromium/components/spellcheck/renderer/spellcheck_worditerator.cc
index 8fe8a6df381..ec16fefbebc 100644
--- a/chromium/components/spellcheck/renderer/spellcheck_worditerator.cc
+++ b/chromium/components/spellcheck/renderer/spellcheck_worditerator.cc
@@ -35,6 +35,24 @@ void SpellcheckCharAttribute::SetDefaultLanguage(const std::string& language) {
CreateRuleSets(language);
}
+bool SpellcheckCharAttribute::IsTextInSameScript(
+ const base::string16& text) const {
+ const base::char16* data = text.data();
+ const size_t length = text.length();
+ for (size_t index = 0; index < length; /* U16_NEXT post-increments */) {
+ uint32_t code = 0;
+ U16_NEXT(data, index, length, code);
+ UErrorCode error = U_ZERO_ERROR;
+ UScriptCode script = uscript_getScript(code, &error);
+ if (U_SUCCESS(error) && (script != USCRIPT_COMMON) &&
+ (script != USCRIPT_INHERITED)) {
+ if (script != script_code_)
+ return false;
+ }
+ }
+ return true;
+}
+
base::string16 SpellcheckCharAttribute::GetRuleSet(
bool allow_contraction) const {
return allow_contraction ?
diff --git a/chromium/components/spellcheck/renderer/spellcheck_worditerator.h b/chromium/components/spellcheck/renderer/spellcheck_worditerator.h
index cf3d6cf1efb..a58901cba81 100644
--- a/chromium/components/spellcheck/renderer/spellcheck_worditerator.h
+++ b/chromium/components/spellcheck/renderer/spellcheck_worditerator.h
@@ -40,6 +40,10 @@ class SpellcheckCharAttribute {
// GetRuleSet() returns the rule-sets created in this function.
void SetDefaultLanguage(const std::string& language);
+ // Returns true if all the characters in a text string are in the script
+ // associated with the spellcheck language.
+ bool IsTextInSameScript(const base::string16& text) const;
+
// Returns a custom rule-set string used by the ICU break iterator. This class
// has two rule-sets, one splits a contraction and the other does not, so we
// can split a concaticated word (e.g. "seven-year-old") into words (e.g.
diff --git a/chromium/components/spellcheck/renderer/spellcheck_worditerator_unittest.cc b/chromium/components/spellcheck/renderer/spellcheck_worditerator_unittest.cc
index 4ab4c4f3ac3..f18f7ff3c6e 100644
--- a/chromium/components/spellcheck/renderer/spellcheck_worditerator_unittest.cc
+++ b/chromium/components/spellcheck/renderer/spellcheck_worditerator_unittest.cc
@@ -505,3 +505,75 @@ TEST(SpellcheckWordIteratorTest, FindSkippableWordsKhmer) {
EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_SKIPPABLE_WORD);
EXPECT_FALSE(iter.Advance());
}
+
+TEST(SpellcheckCharAttributeTest, IsTextInSameScript) {
+ struct LanguageWithSampleText {
+ const char* language;
+ const wchar_t* sample_text;
+ };
+
+ static const std::vector<LanguageWithSampleText> kLanguagesWithSampleText = {
+ // Latin
+ {"fr", L"Libert\x00e9, \x00e9galitt\x00e9, fraternit\x00e9."},
+ // Greek
+ {"el", L"\x03B3\x03B5\x03B9\x03AC\x0020\x03C3\x03BF\x03C5"},
+ // Cyrillic
+ {"ru",
+ L"\x0437\x0434\x0440\x0430\x0432\x0441\x0442\x0432\x0443\x0439\x0442"
+ L"\x0435"},
+ // Hebrew
+ {"he", L"\x05e9\x05c1\x05b8\x05dc\x05d5\x05b9\x05dd"},
+ // Arabic
+ {"ar",
+ L"\x0627\x064e\x0644\x0633\x064e\x0651\x0644\x0627\x0645\x064f\x0639"
+ L"\x064e\x0644\x064e\x064a\x0652\x0643\x064f\x0645\x0652 "},
+ // Hindi
+ {"hi", L"\x0930\x093E\x091C\x0927\x093E\x0928"},
+ // Thai
+ {"th",
+ L"\x0e2a\x0e27\x0e31\x0e2a\x0e14\x0e35\x0020\x0e04\x0e23\x0e31\x0e1a"},
+ // Hiragata
+ {"jp-Hira", L"\x3053\x3093\x306B\x3061\x306F"},
+ // Katakana
+ {"jp-Kana", L"\x30b3\x30de\x30fc\x30b9"},
+ // CJKV ideographs
+ {"zh-Hani", L"\x4F60\x597D"},
+ // Hangul Syllables
+ {"ko", L"\xC548\xB155\xD558\xC138\xC694"},
+ };
+
+ for (const auto& testcase : kLanguagesWithSampleText) {
+ SpellcheckCharAttribute attribute;
+ attribute.SetDefaultLanguage(testcase.language);
+ base::string16 sample_text(base::WideToUTF16(testcase.sample_text));
+ EXPECT_TRUE(attribute.IsTextInSameScript(sample_text))
+ << "Language \"" << testcase.language
+ << "\" fails to identify that sample text in same language is in same "
+ "script.";
+
+ // All other scripts in isolatation or mixed with current script should
+ // return false.
+ for (const auto& other_script : kLanguagesWithSampleText) {
+ if (testcase.language == other_script.language)
+ continue;
+ base::string16 other_sample_text(
+ base::WideToUTF16(other_script.sample_text));
+ EXPECT_FALSE(attribute.IsTextInSameScript(other_sample_text))
+ << "Language \"" << testcase.language
+ << "\" fails to identify that sample text in language \""
+ << other_script.language << "\" is in different script.";
+ EXPECT_FALSE(
+ attribute.IsTextInSameScript(sample_text + other_sample_text))
+ << "Language \"" << testcase.language
+ << "\" fails to identify that sample text in language \""
+ << other_script.language
+ << "\" is in different script when appended to text in this script.";
+ EXPECT_FALSE(
+ attribute.IsTextInSameScript(other_sample_text + sample_text))
+ << "Language \"" << testcase.language
+ << "\" fails to identify that sample text in language \""
+ << other_script.language
+ << "\" is in different script when prepended to text in this script.";
+ }
+ }
+}
diff --git a/chromium/components/spellcheck/renderer/spelling_engine.cc b/chromium/components/spellcheck/renderer/spelling_engine.cc
index 5d27e2cbede..c2b048bab47 100644
--- a/chromium/components/spellcheck/renderer/spelling_engine.cc
+++ b/chromium/components/spellcheck/renderer/spelling_engine.cc
@@ -20,29 +20,19 @@
SpellingEngine* CreateNativeSpellingEngine(
service_manager::LocalInterfaceProvider* embedder_provider) {
DCHECK(embedder_provider);
-#if BUILDFLAG(USE_BROWSER_SPELLCHECKER)
#if defined(OS_WIN)
- if (spellcheck::UseWinHybridSpellChecker()) {
- // On Windows, when using the hybrid spellchecker, both Hunspell and the
- // platform are used for spellchecking. Ideally we'd want to know which
- // languages are supported by the platform spellchecker, and only create a
- // HunspellEngine for languages that aren't. Unfortunately, performing that
- // check must be done asynchronously on the browser side, while this
- // function must return synchronously. However, because the platform
- // spellchecker uses a code path that does not involve a SpellingEngine when
- // performing spellchecking, a solution is to create a HunspellEngine for
- // every language, even those that the platform supports. Because the
- // languages that the platform spellchecker supports are initialized on the
- // browser side, the HunspellEngine returned here will remain disabled for
- // these languages, so they will be skipped when performing the Hunspell
- // check.
- return new HunspellEngine(embedder_provider);
- } else if (spellcheck::UseBrowserSpellChecker()) {
- return new PlatformSpellingEngine(embedder_provider);
- }
-#else
- return new PlatformSpellingEngine(embedder_provider);
+ // On Windows, always return a HunspellEngine. This is a simplification to
+ // avoid needing an async Mojo call to the browser process to determine which
+ // languages are supported by the native spell checker. Returning a
+ // HunspellEngine for languages supported by the native spell checker is
+ // harmless because the SpellingEngine object returned here is never used
+ // during native spell checking. It also doesn't affect Hunspell, since these
+ // languages are skipped during the Hunspell check.
+ return new HunspellEngine(embedder_provider);
#endif // defined(OS_WIN)
+
+#if BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+ return new PlatformSpellingEngine(embedder_provider);
#endif // BUILDFLAG(USE_BROWSER_SPELLCHECKER)
#if BUILDFLAG(USE_RENDERER_SPELLCHECKER)