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

Side by Side Diff: chrome/browser/spellchecker/spellchecker_mac.mm

Issue 8890022: Remove Hunspell on OS X - step 2 (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Fix namespace name Created 9 years 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2011 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 // This file implements the interface defined in spellchecker_platform_engine.h
6 // for the OS X platform.
7
8 #include "chrome/browser/spellchecker/spellchecker_platform_engine.h"
9
10 #import <Cocoa/Cocoa.h>
11
12 #include "base/logging.h"
13 #include "base/metrics/histogram.h"
14 #include "base/sys_string_conversions.h"
15 #include "base/task.h"
16 #include "base/time.h"
17 #include "chrome/common/spellcheck_common.h"
18 #include "chrome/common/spellcheck_messages.h"
19 #include "content/browser/browser_message_filter.h"
20 #include "content/public/browser/browser_thread.h"
21 #include "third_party/WebKit/Source/WebKit/chromium/public/WebTextCheckingResult .h"
22
23 using base::TimeTicks;
24 using content::BrowserThread;
25
26 namespace {
27 // The number of characters in the first part of the language code.
28 const unsigned int kShortLanguageCodeSize = 2;
29
30 // TextCheckingTask is reserved for spell checking against large size
31 // of text, which possible contains multiple paragrpahs. Checking
32 // that size of text might take time, and should be done as a task on
33 // the FILE thread.
34 //
35 // The result of the check is returned back as a
36 // SpellCheckMsg_RespondTextCheck message.
37 class TextCheckingTask : public Task {
38 public:
39 TextCheckingTask(BrowserMessageFilter* destination,
40 int route_id,
41 int identifier,
42 const string16& text,
43 int document_tag)
44 : destination_(destination),
45 route_id_(route_id),
46 identifier_(identifier),
47 text_(text),
48 document_tag_(document_tag) {
49 }
50
51 virtual void Run() {
52 // TODO(morrita): Use [NSSpellChecker requestCheckingOfString]
53 // when the build target goes up to 10.6
54 std::vector<WebKit::WebTextCheckingResult> check_results;
55 NSString* text_to_check = base::SysUTF16ToNSString(text_);
56 size_t starting_at = 0;
57 while (starting_at < text_.size()) {
58 NSRange range = [[NSSpellChecker sharedSpellChecker]
59 checkSpellingOfString:text_to_check
60 startingAt:starting_at
61 language:nil
62 wrap:NO
63 inSpellDocumentWithTag:document_tag_
64 wordCount:NULL];
65 if (range.length == 0)
66 break;
67 check_results.push_back(WebKit::WebTextCheckingResult(
68 WebKit::WebTextCheckingResult::ErrorSpelling,
69 range.location,
70 range.length));
71 starting_at = range.location + range.length;
72 }
73
74 BrowserThread::PostTask(
75 BrowserThread::IO,
76 FROM_HERE,
77 NewRunnableMethod(
78 destination_.get(),
79 &BrowserMessageFilter::Send,
80 new SpellCheckMsg_RespondTextCheck(route_id_,
81 identifier_,
82 document_tag_,
83 check_results)));
84 }
85
86 private:
87 scoped_refptr<BrowserMessageFilter> destination_;
88 int route_id_;
89 int identifier_;
90 string16 text_;
91 int document_tag_;
92 };
93
94 // A private utility function to convert hunspell language codes to OS X
95 // language codes.
96 NSString* ConvertLanguageCodeToMac(const std::string& hunspell_lang_code) {
97 NSString* whole_code = base::SysUTF8ToNSString(hunspell_lang_code);
98
99 if ([whole_code length] > kShortLanguageCodeSize) {
100 NSString* lang_code = [whole_code
101 substringToIndex:kShortLanguageCodeSize];
102 // Add 1 here to skip the underscore.
103 NSString* region_code = [whole_code
104 substringFromIndex:(kShortLanguageCodeSize + 1)];
105
106 // Check for the special case of en-US and pt-PT, since OS X lists these
107 // as just en and pt respectively.
108 // TODO(pwicks): Find out if there are other special cases for languages
109 // not installed on the system by default. Are there others like pt-PT?
110 if (([lang_code isEqualToString:@"en"] &&
111 [region_code isEqualToString:@"US"]) ||
112 ([lang_code isEqualToString:@"pt"] &&
113 [region_code isEqualToString:@"PT"])) {
114 return lang_code;
115 }
116
117 // Otherwise, just build a string that uses an underscore instead of a
118 // dash between the language and the region code, since this is the
119 // format that OS X uses.
120 NSString* os_x_language =
121 [NSString stringWithFormat:@"%@_%@", lang_code, region_code];
122 return os_x_language;
123 } else {
124 // Special case for Polish.
125 if ([whole_code isEqualToString:@"pl"]) {
126 return @"pl_PL";
127 }
128 // This is just a language code with the same format as OS X
129 // language code.
130 return whole_code;
131 }
132 }
133
134 std::string ConvertLanguageCodeFromMac(NSString* lang_code) {
135 // TODO(pwicks):figure out what to do about Multilingual
136 // Guards for strange cases.
137 if ([lang_code isEqualToString:@"en"]) return std::string("en-US");
138 if ([lang_code isEqualToString:@"pt"]) return std::string("pt-PT");
139 if ([lang_code isEqualToString:@"pl_PL"]) return std::string("pl");
140
141 if ([lang_code length] > kShortLanguageCodeSize &&
142 [lang_code characterAtIndex:kShortLanguageCodeSize] == '_') {
143 return base::SysNSStringToUTF8([NSString stringWithFormat:@"%@-%@",
144 [lang_code substringToIndex:kShortLanguageCodeSize],
145 [lang_code substringFromIndex:(kShortLanguageCodeSize + 1)]]);
146 }
147 return base::SysNSStringToUTF8(lang_code);
148 }
149
150 } // namespace
151
152 namespace SpellCheckerPlatform {
153
154 void GetAvailableLanguages(std::vector<std::string>* spellcheck_languages) {
155 NSArray* availableLanguages = [[NSSpellChecker sharedSpellChecker]
156 availableLanguages];
157 for (NSString* lang_code in availableLanguages) {
158 spellcheck_languages->push_back(
159 ConvertLanguageCodeFromMac(lang_code));
160 }
161 }
162
163 bool SpellCheckerAvailable() {
164 // If this file was compiled, then we know that we are on OS X 10.5 at least
165 // and can safely return true here.
166 return true;
167 }
168
169 bool SpellCheckerProvidesPanel() {
170 // OS X has a Spelling Panel, so we can return true here.
171 return true;
172 }
173
174 bool SpellingPanelVisible() {
175 // This should only be called from the main thread.
176 DCHECK([NSThread currentThread] == [NSThread mainThread]);
177 return [[[NSSpellChecker sharedSpellChecker] spellingPanel] isVisible];
178 }
179
180 void ShowSpellingPanel(bool show) {
181 if (show) {
182 [[[NSSpellChecker sharedSpellChecker] spellingPanel]
183 performSelectorOnMainThread:@selector(makeKeyAndOrderFront:)
184 withObject:nil
185 waitUntilDone:YES];
186 } else {
187 [[[NSSpellChecker sharedSpellChecker] spellingPanel]
188 performSelectorOnMainThread:@selector(close)
189 withObject:nil
190 waitUntilDone:YES];
191 }
192 }
193
194 void UpdateSpellingPanelWithMisspelledWord(const string16& word) {
195 NSString * word_to_display = base::SysUTF16ToNSString(word);
196 [[NSSpellChecker sharedSpellChecker]
197 performSelectorOnMainThread:
198 @selector(updateSpellingPanelWithMisspelledWord:)
199 withObject:word_to_display
200 waitUntilDone:YES];
201 }
202
203 void Init() {
204 }
205
206 bool PlatformSupportsLanguage(const std::string& current_language) {
207 // First, convert the language to an OS X language code.
208 NSString* mac_lang_code = ConvertLanguageCodeToMac(current_language);
209
210 // Then grab the languages available.
211 NSArray* availableLanguages;
212 availableLanguages = [[NSSpellChecker sharedSpellChecker]
213 availableLanguages];
214
215 // Return true if the given language is supported by OS X.
216 return [availableLanguages containsObject:mac_lang_code];
217 }
218
219 void SetLanguage(const std::string& lang_to_set) {
220 NSString* NS_lang_to_set = ConvertLanguageCodeToMac(lang_to_set);
221 [[NSSpellChecker sharedSpellChecker] setLanguage:NS_lang_to_set];
222 }
223
224 static int last_seen_tag_;
225
226 bool CheckSpelling(const string16& word_to_check, int tag) {
227 last_seen_tag_ = tag;
228
229 // [[NSSpellChecker sharedSpellChecker] checkSpellingOfString] returns an
230 // NSRange that we can look at to determine if a word is misspelled.
231 NSRange spell_range = {0,0};
232
233 // Convert the word to an NSString.
234 NSString* NS_word_to_check = base::SysUTF16ToNSString(word_to_check);
235 // Check the spelling, starting at the beginning of the word.
236 spell_range = [[NSSpellChecker sharedSpellChecker]
237 checkSpellingOfString:NS_word_to_check startingAt:0
238 language:nil wrap:NO inSpellDocumentWithTag:tag
239 wordCount:NULL];
240
241 // If the length of the misspelled word == 0,
242 // then there is no misspelled word.
243 bool word_correct = (spell_range.length == 0);
244 return word_correct;
245 }
246
247 void FillSuggestionList(const string16& wrong_word,
248 std::vector<string16>* optional_suggestions) {
249 NSString* NS_wrong_word = base::SysUTF16ToNSString(wrong_word);
250 TimeTicks debug_begin_time = base::Histogram::DebugNow();
251 // The suggested words for |wrong_word|.
252 NSArray* guesses =
253 [[NSSpellChecker sharedSpellChecker] guessesForWord:NS_wrong_word];
254 DHISTOGRAM_TIMES("Spellcheck.SuggestTime",
255 base::Histogram::DebugNow() - debug_begin_time);
256
257 for (int i = 0; i < static_cast<int>([guesses count]); i++) {
258 if (i < SpellCheckCommon::kMaxSuggestions) {
259 optional_suggestions->push_back(base::SysNSStringToUTF16(
260 [guesses objectAtIndex:i]));
261 }
262 }
263 }
264
265 void AddWord(const string16& word) {
266 NSString* word_to_add = base::SysUTF16ToNSString(word);
267 [[NSSpellChecker sharedSpellChecker] learnWord:word_to_add];
268 }
269
270 void RemoveWord(const string16& word) {
271 NSString *word_to_remove = base::SysUTF16ToNSString(word);
272 [[NSSpellChecker sharedSpellChecker] unlearnWord:word_to_remove];
273 }
274
275 int GetDocumentTag() {
276 NSInteger doc_tag = [NSSpellChecker uniqueSpellDocumentTag];
277 return static_cast<int>(doc_tag);
278 }
279
280 void IgnoreWord(const string16& word) {
281 [[NSSpellChecker sharedSpellChecker] ignoreWord:base::SysUTF16ToNSString(word)
282 inSpellDocumentWithTag:last_seen_tag_];
283 }
284
285 void CloseDocumentWithTag(int tag) {
286 [[NSSpellChecker sharedSpellChecker]
287 closeSpellDocumentWithTag:static_cast<NSInteger>(tag)];
288 }
289
290 void RequestTextCheck(int route_id,
291 int identifier,
292 int document_tag,
293 const string16& text, BrowserMessageFilter* destination) {
294 BrowserThread::PostTask(
295 BrowserThread::FILE, FROM_HERE,
296 new TextCheckingTask(
297 destination, route_id, identifier, text, document_tag));
298 }
299
300 } // namespace SpellCheckerPlatform
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698