#ifdef UNSAFE_BUFFERS_BUILD
#pragma allow_unsafe_buffers
#endif
#include "components/spellcheck/renderer/spellcheck_provider.h"
#include <unordered_map>
#include "base/functional/bind.h"
#include "base/memory/raw_ptr.h"
#include "base/metrics/histogram_macros.h"
#include "base/ranges/algorithm.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "components/spellcheck/common/spellcheck.mojom.h"
#include "components/spellcheck/common/spellcheck_common.h"
#include "components/spellcheck/common/spellcheck_features.h"
#include "components/spellcheck/common/spellcheck_result.h"
#include "components/spellcheck/renderer/spellcheck.h"
#include "components/spellcheck/renderer/spellcheck_language.h"
#include "components/spellcheck/renderer/spellcheck_renderer_metrics.h"
#include "components/spellcheck/spellcheck_buildflags.h"
#include "content/public/renderer/render_frame.h"
#include "content/public/renderer/render_thread.h"
#include "services/service_manager/public/cpp/local_interface_provider.h"
#include "third_party/blink/public/platform/browser_interface_broker_proxy.h"
#include "third_party/blink/public/platform/web_vector.h"
#include "third_party/blink/public/web/web_document.h"
#include "third_party/blink/public/web/web_element.h"
#include "third_party/blink/public/web/web_local_frame.h"
#include "third_party/blink/public/web/web_text_checking_completion.h"
#include "third_party/blink/public/web/web_text_checking_result.h"
#include "third_party/blink/public/web/web_text_decoration_type.h"
WebElement;
WebLocalFrame;
WebString;
WebTextCheckingCompletion;
WebTextCheckingResult;
WebTextDecorationType;
WebVector;
static_assert …;
static_assert …;
class SpellCheckProvider::DictionaryUpdateObserverImpl
: public DictionaryUpdateObserver { … };
SpellCheckProvider::DictionaryUpdateObserverImpl::DictionaryUpdateObserverImpl(
SpellCheckProvider* owner)
: … { … }
SpellCheckProvider::DictionaryUpdateObserverImpl::
~DictionaryUpdateObserverImpl() { … }
void SpellCheckProvider::DictionaryUpdateObserverImpl::OnDictionaryUpdated(
const WebVector<WebString>& words_added) { … }
SpellCheckProvider::SpellCheckProvider(content::RenderFrame* render_frame,
SpellCheck* spellcheck)
: … { … }
SpellCheckProvider::~SpellCheckProvider() { … }
void SpellCheckProvider::ResetDictionaryUpdateObserverForTesting() { … }
void SpellCheckProvider::RequestTextChecking(
const std::u16string& text,
std::unique_ptr<WebTextCheckingCompletion> completion) { … }
#if BUILDFLAG(USE_BROWSER_SPELLCHECKER)
void SpellCheckProvider::RequestTextCheckingFromBrowser(
const std::u16string& text) {
DCHECK(spellcheck::UseBrowserSpellChecker());
#if BUILDFLAG(IS_WIN)
bool use_hunspell = spellcheck_->EnabledLanguageCount() > 0;
bool use_native =
spellcheck_->EnabledLanguageCount() != spellcheck_->LanguageCount();
if (!use_hunspell && !use_native) {
OnRespondTextCheck(last_identifier_, text, {});
return;
}
if (!use_native) {
GetSpellCheckHost().CallSpellingService(
text,
base::BindOnce(&SpellCheckProvider::OnRespondSpellingService,
weak_factory_.GetWeakPtr(), last_identifier_, text));
return;
}
hybrid_requests_info_[last_identifier_] = {use_hunspell,
use_native,
base::TimeTicks::Now()};
#endif
GetSpellCheckHost().RequestTextCheck(
text, base::BindOnce(&SpellCheckProvider::OnRespondTextCheck,
weak_factory_.GetWeakPtr(), last_identifier_, text));
}
#if BUILDFLAG(IS_WIN)
void SpellCheckProvider::OnRespondInitializeDictionaries(
const std::u16string& text,
std::vector<spellcheck::mojom::SpellCheckBDictLanguagePtr> dictionaries,
const std::vector<std::string>& custom_words,
bool enable) {
DCHECK(!dictionaries_loaded_);
dictionaries_loaded_ = true;
spellcheck_->Initialize(std::move(dictionaries), custom_words, enable);
RequestTextCheckingFromBrowser(text);
}
#endif
#endif
void SpellCheckProvider::FocusedElementChanged(
const blink::WebElement& unused) { … }
spellcheck::mojom::SpellCheckHost& SpellCheckProvider::GetSpellCheckHost() { … }
bool SpellCheckProvider::IsSpellCheckingEnabled() const { … }
void SpellCheckProvider::CheckSpelling(
const WebString& text,
size_t& offset,
size_t& length,
blink::WebVector<blink::WebString>* optional_suggestions) { … }
void SpellCheckProvider::RequestCheckingOfText(
const WebString& text,
std::unique_ptr<WebTextCheckingCompletion> completion) { … }
#if BUILDFLAG(USE_RENDERER_SPELLCHECKER)
void SpellCheckProvider::OnRespondSpellingService(
int identifier,
const std::u16string& line,
bool success,
const std::vector<SpellCheckResult>& results) { … }
#endif
bool SpellCheckProvider::HasWordCharacters(const std::u16string& text,
size_t index) const { … }
#if BUILDFLAG(USE_BROWSER_SPELLCHECKER)
void SpellCheckProvider::OnRespondTextCheck(
int identifier,
const std::u16string& line,
const std::vector<SpellCheckResult>& results) {
DCHECK(spellcheck_);
if (!text_check_completions_.Lookup(identifier))
return;
std::unique_ptr<WebTextCheckingCompletion> completion(
text_check_completions_.Replace(identifier, nullptr));
text_check_completions_.Remove(identifier);
blink::WebVector<blink::WebTextCheckingResult> textcheck_results;
SpellCheck::ResultFilter result_filter = SpellCheck::DO_NOT_MODIFY;
#if BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
const auto& request_info = hybrid_requests_info_.find(identifier);
if (spellcheck::UseBrowserSpellChecker() &&
request_info != hybrid_requests_info_.end() &&
request_info->second.used_hunspell && request_info->second.used_native) {
result_filter = SpellCheck::USE_HUNSPELL_FOR_HYBRID_CHECK;
}
#endif
spellcheck_->CreateTextCheckingResults(result_filter, GetSpellCheckHost(),
0, line, results,
&textcheck_results);
#if BUILDFLAG(IS_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
completion->DidFinishCheckingText(textcheck_results);
last_request_ = line;
last_results_.swap(textcheck_results);
}
#endif
bool SpellCheckProvider::SatisfyRequestFromCache(
const std::u16string& text,
WebTextCheckingCompletion* completion) { … }
void SpellCheckProvider::OnDestruct() { … }