Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2031)

Unified Diff: chrome/renderer/spellchecker/spellcheck.cc

Issue 2198143002: Componentize spellcheck [3]: move renderer/ files to component. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/renderer/spellchecker/spellcheck.h ('k') | chrome/renderer/spellchecker/spellcheck_language.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/renderer/spellchecker/spellcheck.cc
diff --git a/chrome/renderer/spellchecker/spellcheck.cc b/chrome/renderer/spellchecker/spellcheck.cc
deleted file mode 100644
index d548285588111b220e2e805dc3465a43555951d8..0000000000000000000000000000000000000000
--- a/chrome/renderer/spellchecker/spellcheck.cc
+++ /dev/null
@@ -1,547 +0,0 @@
-// 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/spellcheck.h"
-
-#include <stddef.h>
-#include <stdint.h>
-#include <algorithm>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/single_thread_task_runner.h"
-#include "base/stl_util.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "build/build_config.h"
-#include "chrome/common/channel_info.h"
-#include "chrome/renderer/spellchecker/spellcheck_language.h"
-#include "chrome/renderer/spellchecker/spellcheck_provider.h"
-#include "components/spellcheck/common/spellcheck_common.h"
-#include "components/spellcheck/common/spellcheck_messages.h"
-#include "components/spellcheck/common/spellcheck_result.h"
-#include "components/spellcheck/common/spellcheck_switches.h"
-#include "content/public/renderer/render_thread.h"
-#include "content/public/renderer/render_view.h"
-#include "content/public/renderer/render_view_visitor.h"
-#include "ipc/ipc_platform_file.h"
-#include "third_party/WebKit/public/platform/WebString.h"
-#include "third_party/WebKit/public/platform/WebVector.h"
-#include "third_party/WebKit/public/web/WebTextCheckingCompletion.h"
-#include "third_party/WebKit/public/web/WebTextCheckingResult.h"
-#include "third_party/WebKit/public/web/WebTextDecorationType.h"
-#include "third_party/WebKit/public/web/WebView.h"
-
-using blink::WebVector;
-using blink::WebString;
-using blink::WebTextCheckingResult;
-using blink::WebTextDecorationType;
-
-namespace {
-const int kNoOffset = 0;
-const int kNoTag = 0;
-
-class UpdateSpellcheckEnabled : public content::RenderViewVisitor {
- public:
- explicit UpdateSpellcheckEnabled(bool enabled) : enabled_(enabled) {}
- bool Visit(content::RenderView* render_view) override;
-
- private:
- bool enabled_; // New spellcheck-enabled state.
- DISALLOW_COPY_AND_ASSIGN(UpdateSpellcheckEnabled);
-};
-
-bool UpdateSpellcheckEnabled::Visit(content::RenderView* render_view) {
- SpellCheckProvider* provider = SpellCheckProvider::Get(render_view);
- DCHECK(provider);
- provider->EnableSpellcheck(enabled_);
- return true;
-}
-
-class DocumentMarkersCollector : public content::RenderViewVisitor {
- public:
- DocumentMarkersCollector() {}
- ~DocumentMarkersCollector() override {}
- const std::vector<uint32_t>& markers() const { return markers_; }
- bool Visit(content::RenderView* render_view) override;
-
- private:
- std::vector<uint32_t> markers_;
- DISALLOW_COPY_AND_ASSIGN(DocumentMarkersCollector);
-};
-
-bool DocumentMarkersCollector::Visit(content::RenderView* render_view) {
- if (!render_view || !render_view->GetWebView())
- return true;
- WebVector<uint32_t> markers;
- render_view->GetWebView()->spellingMarkers(&markers);
- for (size_t i = 0; i < markers.size(); ++i)
- markers_.push_back(markers[i]);
- // Visit all render views.
- return true;
-}
-
-class DocumentMarkersRemover : public content::RenderViewVisitor {
- public:
- explicit DocumentMarkersRemover(const std::set<std::string>& words);
- ~DocumentMarkersRemover() override {}
- bool Visit(content::RenderView* render_view) override;
-
- private:
- WebVector<WebString> words_;
- DISALLOW_COPY_AND_ASSIGN(DocumentMarkersRemover);
-};
-
-DocumentMarkersRemover::DocumentMarkersRemover(
- const std::set<std::string>& words)
- : words_(words.size()) {
- std::transform(words.begin(), words.end(), words_.begin(),
- [](const std::string& w) { return WebString::fromUTF8(w); });
-}
-
-bool DocumentMarkersRemover::Visit(content::RenderView* render_view) {
- if (render_view && render_view->GetWebView())
- render_view->GetWebView()->removeSpellingMarkersUnderWords(words_);
- return true;
-}
-
-bool IsApostrophe(base::char16 c) {
- const base::char16 kApostrophe = 0x27;
- const base::char16 kRightSingleQuotationMark = 0x2019;
- return c == kApostrophe || c == kRightSingleQuotationMark;
-}
-
-// Makes sure that the apostrophes in the |spelling_suggestion| are the same
-// type as in the |misspelled_word| and in the same order. Ignore differences in
-// the number of apostrophes.
-void PreserveOriginalApostropheTypes(const base::string16& misspelled_word,
- base::string16* spelling_suggestion) {
- auto it = spelling_suggestion->begin();
- for (const base::char16& c : misspelled_word) {
- if (IsApostrophe(c)) {
- it = std::find_if(it, spelling_suggestion->end(), IsApostrophe);
- if (it == spelling_suggestion->end())
- return;
-
- *it++ = c;
- }
- }
-}
-
-} // namespace
-
-class SpellCheck::SpellcheckRequest {
- public:
- SpellcheckRequest(const base::string16& text,
- blink::WebTextCheckingCompletion* completion)
- : text_(text), completion_(completion) {
- DCHECK(completion);
- }
- ~SpellcheckRequest() {}
-
- base::string16 text() { return text_; }
- blink::WebTextCheckingCompletion* completion() { return completion_; }
-
- private:
- base::string16 text_; // Text to be checked in this task.
-
- // The interface to send the misspelled ranges to WebKit.
- blink::WebTextCheckingCompletion* completion_;
-
- DISALLOW_COPY_AND_ASSIGN(SpellcheckRequest);
-};
-
-
-// Initializes SpellCheck object.
-// spellcheck_enabled_ currently MUST be set to true, due to peculiarities of
-// the initialization sequence.
-// Since it defaults to true, newly created SpellCheckProviders will enable
-// spellchecking. After the first word is typed, the provider requests a check,
-// which in turn triggers the delayed initialization sequence in SpellCheck.
-// This does send a message to the browser side, which triggers the creation
-// of the SpellcheckService. That does create the observer for the preference
-// responsible for enabling/disabling checking, which allows subsequent changes
-// to that preference to be sent to all SpellCheckProviders.
-// Setting |spellcheck_enabled_| to false by default prevents that mechanism,
-// and as such the SpellCheckProviders will never be notified of different
-// values.
-// TODO(groby): Simplify this.
-SpellCheck::SpellCheck() : spellcheck_enabled_(true) {}
-
-SpellCheck::~SpellCheck() {
-}
-
-void SpellCheck::FillSuggestions(
- const std::vector<std::vector<base::string16>>& suggestions_list,
- std::vector<base::string16>* optional_suggestions) {
- DCHECK(optional_suggestions);
- size_t num_languages = suggestions_list.size();
-
- // Compute maximum number of suggestions in a single language.
- size_t max_suggestions = 0;
- for (const auto& suggestions : suggestions_list)
- max_suggestions = std::max(max_suggestions, suggestions.size());
-
- for (size_t count = 0; count < (max_suggestions * num_languages); ++count) {
- size_t language = count % num_languages;
- size_t index = count / num_languages;
-
- if (suggestions_list[language].size() <= index)
- continue;
-
- const base::string16& suggestion = suggestions_list[language][index];
- // Only add the suggestion if it's unique.
- if (!ContainsValue(*optional_suggestions, suggestion)) {
- optional_suggestions->push_back(suggestion);
- }
- if (optional_suggestions->size() >= spellcheck::kMaxSuggestions) {
- break;
- }
- }
-}
-
-bool SpellCheck::OnControlMessageReceived(const IPC::Message& message) {
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(SpellCheck, message)
- IPC_MESSAGE_HANDLER(SpellCheckMsg_Init, OnInit)
- IPC_MESSAGE_HANDLER(SpellCheckMsg_CustomDictionaryChanged,
- OnCustomDictionaryChanged)
- IPC_MESSAGE_HANDLER(SpellCheckMsg_EnableSpellCheck, OnEnableSpellCheck)
- IPC_MESSAGE_HANDLER(SpellCheckMsg_RequestDocumentMarkers,
- OnRequestDocumentMarkers)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
-
- return handled;
-}
-
-void SpellCheck::OnInit(
- const std::vector<SpellCheckBDictLanguage>& bdict_languages,
- const std::set<std::string>& custom_words) {
- languages_.clear();
- for (const auto& bdict_language : bdict_languages) {
- AddSpellcheckLanguage(
- IPC::PlatformFileForTransitToFile(bdict_language.file),
- bdict_language.language);
- }
-
- custom_dictionary_.Init(custom_words);
-#if !defined(USE_BROWSER_SPELLCHECKER)
- PostDelayedSpellCheckTask(pending_request_param_.release());
-#endif
-}
-
-void SpellCheck::OnCustomDictionaryChanged(
- const std::set<std::string>& words_added,
- const std::set<std::string>& words_removed) {
- custom_dictionary_.OnCustomDictionaryChanged(words_added, words_removed);
- if (words_added.empty())
- return;
- DocumentMarkersRemover markersRemover(words_added);
- content::RenderView::ForEach(&markersRemover);
-}
-
-void SpellCheck::OnEnableSpellCheck(bool enable) {
- spellcheck_enabled_ = enable;
- UpdateSpellcheckEnabled updater(enable);
- content::RenderView::ForEach(&updater);
-}
-
-void SpellCheck::OnRequestDocumentMarkers() {
- DocumentMarkersCollector collector;
- content::RenderView::ForEach(&collector);
- content::RenderThread::Get()->Send(
- new SpellCheckHostMsg_RespondDocumentMarkers(collector.markers()));
-}
-
-// TODO(groby): Make sure we always have a spelling engine, even before
-// AddSpellcheckLanguage() is called.
-void SpellCheck::AddSpellcheckLanguage(base::File file,
- const std::string& language) {
- languages_.push_back(new SpellcheckLanguage());
- languages_.back()->Init(std::move(file), language);
-}
-
-bool SpellCheck::SpellCheckWord(
- const base::char16* text_begin,
- int position_in_text,
- int text_length,
- int tag,
- int* misspelling_start,
- int* misspelling_len,
- std::vector<base::string16>* optional_suggestions) {
- DCHECK(text_length >= position_in_text);
- DCHECK(misspelling_start && misspelling_len) << "Out vars must be given.";
-
- // Do nothing if we need to delay initialization. (Rather than blocking,
- // report the word as correctly spelled.)
- if (InitializeIfNeeded())
- return true;
-
- // These are for holding misspelling or skippable word positions and lengths
- // between calls to SpellcheckLanguage::SpellCheckWord.
- int possible_misspelling_start;
- int possible_misspelling_len;
- // The longest sequence of text that all languages agree is skippable.
- int agreed_skippable_len;
- // A vector of vectors containing spelling suggestions from different
- // languages.
- std::vector<std::vector<base::string16>> suggestions_list;
- // A vector to hold a language's misspelling suggestions between spellcheck
- // calls.
- std::vector<base::string16> language_suggestions;
-
- // This loop only advances if all languages agree that a sequence of text is
- // skippable.
- for (; position_in_text <= text_length;
- position_in_text += agreed_skippable_len) {
- // Reseting |agreed_skippable_len| to the worst-case length each time
- // prevents some unnecessary iterations.
- agreed_skippable_len = text_length;
- *misspelling_start = 0;
- *misspelling_len = 0;
- suggestions_list.clear();
-
- for (ScopedVector<SpellcheckLanguage>::iterator language =
- languages_.begin();
- language != languages_.end();) {
- language_suggestions.clear();
- SpellcheckLanguage::SpellcheckWordResult result =
- (*language)->SpellCheckWord(
- text_begin, position_in_text, text_length, tag,
- &possible_misspelling_start, &possible_misspelling_len,
- optional_suggestions ? &language_suggestions : nullptr);
-
- switch (result) {
- case SpellcheckLanguage::SpellcheckWordResult::IS_CORRECT:
- *misspelling_start = 0;
- *misspelling_len = 0;
- return true;
- case SpellcheckLanguage::SpellcheckWordResult::IS_SKIPPABLE:
- agreed_skippable_len =
- std::min(agreed_skippable_len, possible_misspelling_len);
- // If true, this means the spellchecker moved past a word that was
- // previously determined to be misspelled or skippable, which means
- // another spellcheck language marked it as correct.
- if (position_in_text != possible_misspelling_start) {
- *misspelling_len = 0;
- position_in_text = possible_misspelling_start;
- suggestions_list.clear();
- language = languages_.begin();
- } else {
- language++;
- }
- break;
- case SpellcheckLanguage::SpellcheckWordResult::IS_MISSPELLED:
- *misspelling_start = possible_misspelling_start;
- *misspelling_len = possible_misspelling_len;
- // If true, this means the spellchecker moved past a word that was
- // previously determined to be misspelled or skippable, which means
- // another spellcheck language marked it as correct.
- if (position_in_text != *misspelling_start) {
- suggestions_list.clear();
- language = languages_.begin();
- position_in_text = *misspelling_start;
- } else {
- suggestions_list.push_back(language_suggestions);
- language++;
- }
- break;
- }
- }
-
- // If |*misspelling_len| is non-zero, that means at least one language
- // marked a word misspelled and no other language considered it correct.
- if (*misspelling_len != 0) {
- if (optional_suggestions)
- FillSuggestions(suggestions_list, optional_suggestions);
- return false;
- }
- }
-
- NOTREACHED();
- return true;
-}
-
-bool SpellCheck::SpellCheckParagraph(
- const base::string16& text,
- WebVector<WebTextCheckingResult>* results) {
-#if !defined(USE_BROWSER_SPELLCHECKER)
- // Mac and Android have their own spell checkers,so this method won't be used
- DCHECK(results);
- std::vector<WebTextCheckingResult> textcheck_results;
- size_t length = text.length();
- size_t position_in_text = 0;
-
- // Spellcheck::SpellCheckWord() automatically breaks text into words and
- // checks the spellings of the extracted words. This function sets the
- // position and length of the first misspelled word and returns false when
- // the text includes misspelled words. Therefore, we just repeat calling the
- // function until it returns true to check the whole text.
- int misspelling_start = 0;
- int misspelling_length = 0;
- while (position_in_text <= length) {
- if (SpellCheckWord(text.c_str(),
- position_in_text,
- length,
- kNoTag,
- &misspelling_start,
- &misspelling_length,
- NULL)) {
- results->assign(textcheck_results);
- return true;
- }
-
- if (!custom_dictionary_.SpellCheckWord(
- text, misspelling_start, misspelling_length)) {
- base::string16 replacement;
- textcheck_results.push_back(WebTextCheckingResult(
- blink::WebTextDecorationTypeSpelling,
- misspelling_start,
- misspelling_length,
- replacement));
- }
- position_in_text = misspelling_start + misspelling_length;
- }
- results->assign(textcheck_results);
- return false;
-#else
- // This function is only invoked for spell checker functionality that runs
- // on the render thread. OSX and Android builds don't have that.
- NOTREACHED();
- return true;
-#endif
-}
-
-// OSX and Android use their own spell checkers
-#if !defined(USE_BROWSER_SPELLCHECKER)
-void SpellCheck::RequestTextChecking(
- const base::string16& text,
- blink::WebTextCheckingCompletion* completion) {
- // Clean up the previous request before starting a new request.
- if (pending_request_param_.get())
- pending_request_param_->completion()->didCancelCheckingText();
-
- pending_request_param_.reset(new SpellcheckRequest(
- text, completion));
- // We will check this text after we finish loading the hunspell dictionary.
- if (InitializeIfNeeded())
- return;
-
- PostDelayedSpellCheckTask(pending_request_param_.release());
-}
-#endif
-
-bool SpellCheck::InitializeIfNeeded() {
- if (languages_.empty())
- return true;
-
- bool initialize_if_needed = false;
- for (SpellcheckLanguage* language : languages_)
- initialize_if_needed |= language->InitializeIfNeeded();
-
- return initialize_if_needed;
-}
-
-// OSX and Android don't have |pending_request_param_|
-#if !defined(USE_BROWSER_SPELLCHECKER)
-void SpellCheck::PostDelayedSpellCheckTask(SpellcheckRequest* request) {
- if (!request)
- return;
-
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(&SpellCheck::PerformSpellCheck, AsWeakPtr(),
- base::Owned(request)));
-}
-#endif
-
-// Mac and Android use their platform engines instead.
-#if !defined(USE_BROWSER_SPELLCHECKER)
-void SpellCheck::PerformSpellCheck(SpellcheckRequest* param) {
- DCHECK(param);
-
- if (languages_.empty() ||
- std::find_if(languages_.begin(), languages_.end(),
- [](SpellcheckLanguage* language) {
- return !language->IsEnabled();
- }) != languages_.end()) {
- param->completion()->didCancelCheckingText();
- } else {
- WebVector<blink::WebTextCheckingResult> results;
- SpellCheckParagraph(param->text(), &results);
- param->completion()->didFinishCheckingText(results);
- }
-}
-#endif
-
-void SpellCheck::CreateTextCheckingResults(
- ResultFilter filter,
- int line_offset,
- const base::string16& line_text,
- const std::vector<SpellCheckResult>& spellcheck_results,
- WebVector<WebTextCheckingResult>* textcheck_results) {
- DCHECK(!line_text.empty());
-
- std::vector<WebTextCheckingResult> results;
- for (const SpellCheckResult& spellcheck_result : spellcheck_results) {
- DCHECK_LE(static_cast<size_t>(spellcheck_result.location),
- line_text.length());
- DCHECK_LE(static_cast<size_t>(spellcheck_result.location +
- spellcheck_result.length),
- line_text.length());
-
- const base::string16& misspelled_word =
- line_text.substr(spellcheck_result.location, spellcheck_result.length);
- base::string16 replacement = spellcheck_result.replacement;
- SpellCheckResult::Decoration decoration = spellcheck_result.decoration;
-
- // Ignore words in custom dictionary.
- if (custom_dictionary_.SpellCheckWord(misspelled_word, 0,
- misspelled_word.length())) {
- continue;
- }
-
- // Use the same types of appostrophes as in the mispelled word.
- PreserveOriginalApostropheTypes(misspelled_word, &replacement);
-
- // Ignore misspellings due the typographical apostrophe.
- if (misspelled_word == replacement)
- continue;
-
- if (filter == USE_NATIVE_CHECKER) {
- // Double-check misspelled words with out spellchecker and attach grammar
- // markers to them if our spellchecker tells us they are correct words,
- // i.e. they are probably contextually-misspelled words.
- int unused_misspelling_start = 0;
- int unused_misspelling_length = 0;
- if (decoration == SpellCheckResult::SPELLING &&
- SpellCheckWord(misspelled_word.c_str(), kNoOffset,
- misspelled_word.length(), kNoTag,
- &unused_misspelling_start, &unused_misspelling_length,
- nullptr)) {
- decoration = SpellCheckResult::GRAMMAR;
- }
- }
-
- results.push_back(WebTextCheckingResult(
- static_cast<WebTextDecorationType>(decoration),
- line_offset + spellcheck_result.location, spellcheck_result.length,
- replacement, spellcheck_result.hash));
- }
-
- textcheck_results->assign(results);
-}
-
-bool SpellCheck::IsSpellcheckEnabled() {
-#if defined(OS_ANDROID)
- if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
- spellcheck::switches::kEnableAndroidSpellChecker)) {
- return false;
- }
-#endif
- return spellcheck_enabled_;
-}
« no previous file with comments | « chrome/renderer/spellchecker/spellcheck.h ('k') | chrome/renderer/spellchecker/spellcheck_language.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698