[GTK] Build error with -DENABLE_SPELLCHECK=OFF
[WebKit.git] / Source / WebKit2 / UIProcess / gtk / TextCheckerGtk.cpp
1 /*
2  * Copyright (C) 2010 Apple Inc. All rights reserved.
3  * Portions Copyright (c) 2010 Motorola Mobility, Inc.  All rights reserved.
4  * Copyright (C) 2011-2013 Samsung Electronics
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
17  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
19  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
25  * THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #include "config.h"
29 #include "TextChecker.h"
30
31 #include "TextBreakIterator.h"
32 #include "TextCheckerState.h"
33 #include "WebProcessPool.h"
34 #include <WebCore/NotImplemented.h>
35 #include <WebCore/TextCheckerEnchant.h>
36 #include <wtf/NeverDestroyed.h>
37
38 using namespace WebCore;
39
40 namespace WebKit {
41
42 #if ENABLE(SPELLCHECK)
43 static WebCore::TextCheckerEnchant& enchantTextChecker()
44 {
45     static NeverDestroyed<WebCore::TextCheckerEnchant> checker;
46     return checker;
47 }
48 #endif
49
50 TextCheckerState& checkerState()
51 {
52     static TextCheckerState textCheckerState;
53     static std::once_flag onceFlag;
54     std::call_once(onceFlag, [] {
55         textCheckerState.isContinuousSpellCheckingEnabled = false;
56         textCheckerState.isGrammarCheckingEnabled = false;
57     });
58
59     return textCheckerState;
60 }
61
62 const TextCheckerState& TextChecker::state()
63 {
64     return checkerState();
65 }
66
67 #if ENABLE(SPELLCHECK)
68 static void updateStateForAllProcessPools()
69 {
70     for (const auto& processPool : WebProcessPool::allProcessPools())
71         processPool->textCheckerStateChanged();
72 }
73 #endif
74
75 bool TextChecker::isContinuousSpellCheckingAllowed()
76 {
77 #if ENABLE(SPELLCHECK)
78     return true;
79 #else
80     return false;
81 #endif
82 }
83
84 void TextChecker::setContinuousSpellCheckingEnabled(bool isContinuousSpellCheckingEnabled)
85 {
86 #if ENABLE(SPELLCHECK)
87     if (checkerState().isContinuousSpellCheckingEnabled == isContinuousSpellCheckingEnabled)
88         return;
89     checkerState().isContinuousSpellCheckingEnabled = isContinuousSpellCheckingEnabled;
90     updateStateForAllProcessPools();
91 #else
92     UNUSED_PARAM(isContinuousSpellCheckingEnabled);
93 #endif
94 }
95
96 void TextChecker::setGrammarCheckingEnabled(bool isGrammarCheckingEnabled)
97 {
98 #if ENABLE(SPELLCHECK)
99     if (checkerState().isGrammarCheckingEnabled == isGrammarCheckingEnabled)
100         return;
101     checkerState().isGrammarCheckingEnabled = isGrammarCheckingEnabled;
102     updateStateForAllProcessPools();
103 #else
104     UNUSED_PARAM(isGrammarCheckingEnabled);
105 #endif
106 }
107
108 void TextChecker::continuousSpellCheckingEnabledStateChanged(bool enabled)
109 {
110 #if ENABLE(SPELLCHECK)
111     checkerState().isContinuousSpellCheckingEnabled = enabled;
112 #else
113     UNUSED_PARAM(enabled);
114 #endif
115 }
116
117 void TextChecker::grammarCheckingEnabledStateChanged(bool enabled)
118 {
119 #if ENABLE(SPELLCHECK)
120     checkerState().isGrammarCheckingEnabled = enabled;
121 #else
122     UNUSED_PARAM(enabled);
123 #endif
124 }
125
126 int64_t TextChecker::uniqueSpellDocumentTag(WebPageProxy*)
127 {
128     return 0;
129 }
130
131 void TextChecker::closeSpellDocumentWithTag(int64_t /* tag */)
132 {
133 }
134
135 void TextChecker::checkSpellingOfString(int64_t /* spellDocumentTag */, StringView text, int32_t& misspellingLocation, int32_t& misspellingLength)
136 {
137 #if ENABLE(SPELLCHECK)
138     misspellingLocation = -1;
139     misspellingLength = 0;
140     enchantTextChecker().checkSpellingOfString(text.toStringWithoutCopying(), misspellingLocation, misspellingLength);
141 #else
142     UNUSED_PARAM(text);
143     UNUSED_PARAM(misspellingLocation);
144     UNUSED_PARAM(misspellingLength);
145 #endif
146 }
147
148 void TextChecker::checkGrammarOfString(int64_t /* spellDocumentTag */, StringView /* text */, Vector<WebCore::GrammarDetail>& /* grammarDetails */, int32_t& /* badGrammarLocation */, int32_t& /* badGrammarLength */)
149 {
150 }
151
152 bool TextChecker::spellingUIIsShowing()
153 {
154     return false;
155 }
156
157 void TextChecker::toggleSpellingUIIsShowing()
158 {
159 }
160
161 void TextChecker::updateSpellingUIWithMisspelledWord(int64_t /* spellDocumentTag */, const String& /* misspelledWord */)
162 {
163 }
164
165 void TextChecker::updateSpellingUIWithGrammarString(int64_t /* spellDocumentTag */, const String& /* badGrammarPhrase */, const GrammarDetail& /* grammarDetail */)
166 {
167 }
168
169 void TextChecker::getGuessesForWord(int64_t /* spellDocumentTag */, const String& word, const String& /* context */, Vector<String>& guesses)
170 {
171 #if ENABLE(SPELLCHECK)
172     guesses = enchantTextChecker().getGuessesForWord(word);
173 #else
174     UNUSED_PARAM(word);
175     UNUSED_PARAM(guesses);
176 #endif
177 }
178
179 void TextChecker::learnWord(int64_t /* spellDocumentTag */, const String& word)
180 {
181 #if ENABLE(SPELLCHECK)
182     enchantTextChecker().learnWord(word);
183 #else
184     UNUSED_PARAM(word);
185 #endif
186 }
187
188 void TextChecker::ignoreWord(int64_t /* spellDocumentTag */, const String& word)
189 {
190 #if ENABLE(SPELLCHECK)
191     enchantTextChecker().ignoreWord(word);
192 #else
193     UNUSED_PARAM(word);
194 #endif
195 }
196
197 void TextChecker::requestCheckingOfString(PassRefPtr<TextCheckerCompletion> completion)
198 {
199 #if ENABLE(SPELLCHECK)
200     if (!completion)
201         return;
202
203     TextCheckingRequestData request = completion->textCheckingRequestData();
204     ASSERT(request.sequence() != unrequestedTextCheckingSequence);
205     ASSERT(request.mask() != TextCheckingTypeNone);
206
207     completion->didFinishCheckingText(checkTextOfParagraph(completion->spellDocumentTag(), request.text(), request.mask()));
208 #else
209     UNUSED_PARAM(completion);
210 #endif
211 }
212
213 #if USE(UNIFIED_TEXT_CHECKING) && ENABLE(SPELLCHECK)
214 static unsigned nextWordOffset(StringView text, unsigned currentOffset)
215 {
216     // FIXME: avoid creating textIterator object here, it could be passed as a parameter.
217     //        isTextBreak() leaves the iterator pointing to the first boundary position at
218     //        or after "offset" (ubrk_isBoundary side effect).
219     //        For many word separators, the method doesn't properly determine the boundaries
220     //        without resetting the iterator.
221     TextBreakIterator* textIterator = wordBreakIterator(text);
222     if (!textIterator)
223         return currentOffset;
224
225     unsigned wordOffset = currentOffset;
226     while (wordOffset < text.length() && isTextBreak(textIterator, wordOffset))
227         ++wordOffset;
228
229     // Do not treat the word's boundary as a separator.
230     if (!currentOffset && wordOffset == 1)
231         return currentOffset;
232
233     // Omit multiple separators.
234     if ((wordOffset - currentOffset) > 1)
235         --wordOffset;
236
237     return wordOffset;
238 }
239 #endif
240
241 #if USE(UNIFIED_TEXT_CHECKING)
242 Vector<TextCheckingResult> TextChecker::checkTextOfParagraph(int64_t spellDocumentTag, StringView text, uint64_t checkingTypes)
243 {
244 #if ENABLE(SPELLCHECK)
245     if (!(checkingTypes & TextCheckingTypeSpelling))
246         return Vector<TextCheckingResult>();
247
248     TextBreakIterator* textIterator = wordBreakIterator(text);
249     if (!textIterator)
250         return Vector<TextCheckingResult>();
251
252     // Omit the word separators at the beginning/end of the text to don't unnecessarily
253     // involve the client to check spelling for them.
254     unsigned offset = nextWordOffset(text, 0);
255     unsigned lengthStrip = text.length();
256     while (lengthStrip > 0 && isTextBreak(textIterator, lengthStrip - 1))
257         --lengthStrip;
258
259     Vector<TextCheckingResult> paragraphCheckingResult;
260     while (offset < lengthStrip) {
261         int32_t misspellingLocation = -1;
262         int32_t misspellingLength = 0;
263         checkSpellingOfString(spellDocumentTag, text.substring(offset, lengthStrip - offset), misspellingLocation, misspellingLength);
264         if (!misspellingLength)
265             break;
266
267         TextCheckingResult misspellingResult;
268         misspellingResult.type = TextCheckingTypeSpelling;
269         misspellingResult.location = offset + misspellingLocation;
270         misspellingResult.length = misspellingLength;
271         paragraphCheckingResult.append(misspellingResult);
272         offset += misspellingLocation + misspellingLength;
273         // Generally, we end up checking at the word separator, move to the adjacent word.
274         offset = nextWordOffset(text.substring(0, lengthStrip), offset);
275     }
276     return paragraphCheckingResult;
277 #else
278     UNUSED_PARAM(spellDocumentTag);
279     UNUSED_PARAM(text);
280     UNUSED_PARAM(checkingTypes);
281     return Vector<TextCheckingResult>();
282 #endif // ENABLE(SPELLCHECK)
283 }
284 #endif // USE(UNIFIED_TEXT_CHECKING)
285
286 void TextChecker::setSpellCheckingLanguages(const Vector<String>& languages)
287 {
288 #if ENABLE(SPELLCHECK)
289     enchantTextChecker().updateSpellCheckingLanguages(languages);
290 #else
291     UNUSED_PARAM(languages);
292 #endif
293 }
294
295 Vector<String> TextChecker::loadedSpellCheckingLanguages()
296 {
297 #if ENABLE(SPELLCHECK)
298     return enchantTextChecker().loadedSpellCheckingLanguages();
299 #else
300     return Vector<String>();
301 #endif
302 }
303
304 } // namespace WebKit