1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef COMPONENTS_SPELLCHECK_RENDERER_SPELLCHECK_H_
6 #define COMPONENTS_SPELLCHECK_RENDERER_SPELLCHECK_H_
7 
8 #include <memory>
9 #include <set>
10 #include <string>
11 #include <vector>
12 
13 #include "base/files/file.h"
14 #include "base/gtest_prod_util.h"
15 #include "base/macros.h"
16 #include "base/memory/weak_ptr.h"
17 #include "base/observer_list.h"
18 #include "base/strings/string16.h"
19 #include "build/build_config.h"
20 #include "components/spellcheck/common/spellcheck.mojom.h"
21 #include "components/spellcheck/common/spellcheck_common.h"
22 #include "components/spellcheck/renderer/custom_dictionary_engine.h"
23 #include "components/spellcheck/spellcheck_buildflags.h"
24 #include "mojo/public/cpp/bindings/pending_receiver.h"
25 #include "mojo/public/cpp/bindings/receiver_set.h"
26 
27 class SpellcheckLanguage;
28 struct SpellCheckResult;
29 
30 namespace blink {
31 class WebTextCheckingCompletion;
32 struct WebTextCheckingResult;
33 template <typename T> class WebVector;
34 class WebString;
35 }
36 
37 namespace service_manager {
38 class LocalInterfaceProvider;
39 }
40 
41 class DictionaryUpdateObserver {
42  public:
43   virtual ~DictionaryUpdateObserver() = default;
44   // |words_added| is newly added words to dictionary as correct words.
45   // OnDictionaryUpdated should be called even if |words_added| empty.
46   virtual void OnDictionaryUpdated(
47       const blink::WebVector<blink::WebString>& words_added) = 0;
48 };
49 
50 // TODO(morrita): Needs reorg with SpellCheckProvider.
51 // See http://crbug.com/73699.
52 // Shared spellchecking logic/data for a RenderProcess. All RenderViews use
53 // this object to perform spellchecking tasks.
54 class SpellCheck : public base::SupportsWeakPtr<SpellCheck>,
55                    public spellcheck::mojom::SpellChecker {
56  public:
57   // TODO(groby): I wonder if this can be private, non-mac only.
58   class SpellcheckRequest;
59   enum ResultFilter {
60     // Do not modify results.
61     DO_NOT_MODIFY = 1,
62     // Use Hunspell to double-check the results from the spelling service
63     // (enhanced spell check). If Hunspell doesn't find a mistake, it most
64     // likely means it was a grammar mistake, not a spelling mistake.
65     USE_HUNSPELL_FOR_GRAMMAR,
66     // Use Hunspell to double-check the results from the native spell checker
67     // for locales that it doesn't support. If Hunspell doesn't find a mistake,
68     // it means the misspelling was a false positive, since the word is
69     // correctly spelled in at least one locale.
70     USE_HUNSPELL_FOR_HYBRID_CHECK,
71   };
72 
73   explicit SpellCheck(
74       service_manager::LocalInterfaceProvider* embedder_provider);
75   ~SpellCheck() override;
76 
77   void AddSpellcheckLanguage(base::File file, const std::string& language);
78 
79   // If there are no dictionary files, then this requests them from the browser
80   // and does not block. In this case it returns true.
81   // If there are dictionary files, but their Hunspell has not been loaded, then
82   // this loads their Hunspell.
83   // If each dictionary file's Hunspell is already loaded, this does nothing. In
84   // both the latter cases it returns false, meaning that it is OK to continue
85   // spellchecking.
86   bool InitializeIfNeeded();
87 
88   // SpellCheck a word.
89   // Returns true if spelled correctly for any language in |languages_|, false
90   // otherwise.
91   // If any spellcheck languages failed to initialize, always returns true.
92   // The |tag| parameter should either be a unique identifier for the document
93   // that the word came from (if the current platform requires it), or 0.
94   // In addition, finds the suggested words for a given word
95   // and puts them into |*optional_suggestions|.
96   // If the word is spelled correctly, the vector is empty.
97   // If optional_suggestions is NULL, suggested words will not be looked up.
98   // Note that doing suggest lookups can be slow.
99   bool SpellCheckWord(const base::char16* text_begin,
100                       size_t position_in_text,
101                       size_t text_length,
102                       int tag,
103                       size_t* misspelling_start,
104                       size_t* misspelling_len,
105                       std::vector<base::string16>* optional_suggestions);
106 
107   // Overload of SpellCheckWord where the replacement suggestions are kept
108   // separately per language, instead of combined into a single list. This is
109   // useful if the suggestions must be merged with another list of suggestions,
110   // for example in the case of the Windows hybrid spellchecker.
111   bool SpellCheckWord(
112       const base::char16* text_begin,
113       size_t position_in_text,
114       size_t text_length,
115       int tag,
116       size_t* misspelling_start,
117       size_t* misspelling_len,
118       spellcheck::PerLanguageSuggestions* optional_per_language_suggestions);
119 
120   // Overload of SpellCheckWord for skipping optional suggestions with a
121   // nullptr, used to disambiguate between the other two overloads.
122   bool SpellCheckWord(const base::char16* text_begin,
123                       size_t position_in_text,
124                       size_t text_length,
125                       int tag,
126                       size_t* misspelling_start,
127                       size_t* misspelling_len,
128                       std::nullptr_t null_suggestions_ptr);
129 
130 #if BUILDFLAG(USE_RENDERER_SPELLCHECKER)
131   // SpellCheck a paragraph.
132   // Returns true if |text| is correctly spelled, false otherwise.
133   // If the spellchecker failed to initialize, always returns true.
134   bool SpellCheckParagraph(
135       const base::string16& text,
136       blink::WebVector<blink::WebTextCheckingResult>* results);
137 
138   // Requests to spellcheck the specified text in the background. This function
139   // posts a background task and calls SpellCheckParagraph() in the task.
140   void RequestTextChecking(
141       const base::string16& text,
142       std::unique_ptr<blink::WebTextCheckingCompletion> completion);
143 #endif
144 
145   // Creates a list of WebTextCheckingResult objects (used by WebKit) from a
146   // list of SpellCheckResult objects (used by Chrome). This function also
147   // checks misspelled words returned by the Spelling service and changes the
148   // underline colors of contextually-misspelled words.
149   void CreateTextCheckingResults(
150       ResultFilter filter,
151       int line_offset,
152       const base::string16& line_text,
153       const std::vector<SpellCheckResult>& spellcheck_results,
154       blink::WebVector<blink::WebTextCheckingResult>* textcheck_results);
155 
156   bool IsSpellcheckEnabled();
157 
158   // Add observer on dictionary update event.
159   void AddDictionaryUpdateObserver(DictionaryUpdateObserver* observer);
160   // Remove observer on dictionary update event.
161   void RemoveDictionaryUpdateObserver(DictionaryUpdateObserver* observer);
162 
163   // Binds receivers for the SpellChecker interface.
164   void BindReceiver(
165       mojo::PendingReceiver<spellcheck::mojom::SpellChecker> receiver);
166 
167   // Returns the current number of spell check languages.
168   // Overridden by tests in spellcheck_provider_test.cc (FakeSpellCheck class).
169   virtual size_t LanguageCount();
170 
171   // Returns the current number of spell check languages with enabled engines.
172   // Overridden by tests in spellcheck_provider_test.cc (FakeSpellCheck class).
173   virtual size_t EnabledLanguageCount();
174 
175  private:
176    friend class SpellCheckTest;
177    friend class FakeSpellCheck;
178    FRIEND_TEST_ALL_PREFIXES(SpellCheckTest, GetAutoCorrectionWord_EN_US);
179    FRIEND_TEST_ALL_PREFIXES(SpellCheckTest,
180        RequestSpellCheckMultipleTimesWithoutInitialization);
181 
182    // spellcheck::mojom::SpellChecker:
183    void Initialize(
184        std::vector<spellcheck::mojom::SpellCheckBDictLanguagePtr> dictionaries,
185        const std::vector<std::string>& custom_words,
186        bool enable) override;
187    void CustomDictionaryChanged(
188        const std::vector<std::string>& words_added,
189        const std::vector<std::string>& words_removed) override;
190 
191    // Performs dictionary update notification.
192    void NotifyDictionaryObservers(
193        const blink::WebVector<blink::WebString>& words_added);
194 
195 #if BUILDFLAG(USE_RENDERER_SPELLCHECKER)
196    // Posts delayed spellcheck task and clear it if any.
197    // Takes ownership of |request|.
198    void PostDelayedSpellCheckTask(SpellcheckRequest* request);
199 
200    // Performs spell checking from the request queue.
201    void PerformSpellCheck(SpellcheckRequest* request);
202 
203    // The parameters of a pending background-spellchecking request. When WebKit
204    // sends a background-spellchecking request before initializing hunspell,
205    // we save its parameters and start spellchecking after we finish
206    // initializing hunspell. (When WebKit sends two or more requests, we cancel
207    // the previous requests so we do not have to use vectors.)
208    std::unique_ptr<SpellcheckRequest> pending_request_param_;
209 #endif
210 
211   // Receivers for SpellChecker clients.
212   mojo::ReceiverSet<spellcheck::mojom::SpellChecker> receivers_;
213 
214   // A vector of objects used to actually check spelling, one for each enabled
215   // language.
216   std::vector<std::unique_ptr<SpellcheckLanguage>> languages_;
217 
218   // Custom dictionary spelling engine.
219   CustomDictionaryEngine custom_dictionary_;
220 
221   service_manager::LocalInterfaceProvider* embedder_provider_;
222 
223   // Remember state for spellchecking.
224   bool spellcheck_enabled_;
225 
226   // Observers of update dictionary events.
227   base::ObserverList<DictionaryUpdateObserver>::Unchecked
228       dictionary_update_observers_;
229 
230   base::WeakPtrFactory<SpellCheck> weak_factory_{this};
231 
232   DISALLOW_COPY_AND_ASSIGN(SpellCheck);
233 };
234 
235 #endif  // COMPONENTS_SPELLCHECK_RENDERER_SPELLCHECK_H_
236