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

Side by Side Diff: chrome/renderer/spellchecker/spellcheck.cc

Issue 9169082: Asynchronous spellchecking on Win and Linux (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: Build fix Created 8 years, 8 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/renderer/spellchecker/spellcheck.h" 5 #include "chrome/renderer/spellchecker/spellcheck.h"
6 6
7 #include "base/bind.h"
7 #include "base/file_util.h" 8 #include "base/file_util.h"
8 #include "base/metrics/histogram.h" 9 #include "base/metrics/histogram.h"
10 #include "base/message_loop_proxy.h"
9 #include "base/time.h" 11 #include "base/time.h"
10 #include "base/utf_string_conversions.h" 12 #include "base/utf_string_conversions.h"
11 #include "chrome/common/render_messages.h" 13 #include "chrome/common/render_messages.h"
12 #include "chrome/common/spellcheck_common.h" 14 #include "chrome/common/spellcheck_common.h"
13 #include "chrome/common/spellcheck_messages.h" 15 #include "chrome/common/spellcheck_messages.h"
14 #include "chrome/common/spellcheck_result.h" 16 #include "chrome/common/spellcheck_result.h"
15 #include "content/public/renderer/render_thread.h" 17 #include "content/public/renderer/render_thread.h"
16 #include "third_party/hunspell/src/hunspell/hunspell.hxx" 18 #include "third_party/hunspell/src/hunspell/hunspell.hxx"
19 #include "third_party/WebKit/Source/WebKit/chromium/public/WebTextCheckingComple tion.h"
20 #include "third_party/WebKit/Source/WebKit/chromium/public/WebTextCheckingResult .h"
17 21
18 using base::TimeTicks; 22 using base::TimeTicks;
19 using content::RenderThread; 23 using content::RenderThread;
24 using WebKit::WebVector;
25 using WebKit::WebTextCheckingResult;
26 using WebKit::WebTextCheckingType;
27
28 namespace spellcheck {
29 void ToWebResultList(
30 int offset,
31 const std::vector<SpellCheckResult>& results,
32 WebVector<WebTextCheckingResult>* web_results) {
33 WebVector<WebTextCheckingResult> list(results.size());
34 for (size_t i = 0; i < results.size(); ++i) {
35 list[i] = WebTextCheckingResult(
36 static_cast<WebTextCheckingType>(results[i].type),
37 results[i].location + offset,
38 results[i].length,
39 results[i].replacement);
40 }
41
42 list.swap(*web_results);
43 }
44
45 WebVector<WebTextCheckingResult> ToWebResultList(
46 int offset,
47 const std::vector<SpellCheckResult>& results) {
48 WebVector<WebTextCheckingResult> web_results;
49 ToWebResultList(offset, results, &web_results);
50 return web_results;
51 }
52 } // namespace spellcheck
53
54 class SpellCheck::SpellCheckRequestParam
55 : public base::RefCountedThreadSafe<SpellCheck::SpellCheckRequestParam> {
56 public:
57 SpellCheckRequestParam(const string16& text,
58 int offset,
59 WebKit::WebTextCheckingCompletion* completion)
60 : text_(text),
61 offset_(offset),
62 completion_(completion) {
63 DCHECK(completion);
64 }
65
66 string16 text() {
67 return text_;
68 }
69
70 int offset() {
71 return offset_;
72 }
73
74 WebKit::WebTextCheckingCompletion* completion() {
75 return completion_;
76 }
77
78 private:
79 // Text to be checked in this task.
80 string16 text_;
81
82 // The text offset from the beginning.
83 int offset_;
84
85 // The interface to send the misspelled ranges to WebKit.
86 WebKit::WebTextCheckingCompletion* completion_;
87
88 DISALLOW_COPY_AND_ASSIGN(SpellCheckRequestParam);
89 };
20 90
21 SpellCheck::SpellCheck() 91 SpellCheck::SpellCheck()
22 : file_(base::kInvalidPlatformFileValue), 92 : file_(base::kInvalidPlatformFileValue),
23 auto_spell_correct_turned_on_(false), 93 auto_spell_correct_turned_on_(false),
24 is_using_platform_spelling_engine_(false), 94 is_using_platform_spelling_engine_(false),
25 initialized_(false) { 95 initialized_(false),
96 dictionary_requested_(false) {
26 // Wait till we check the first word before doing any initializing. 97 // Wait till we check the first word before doing any initializing.
27 } 98 }
28 99
29 SpellCheck::~SpellCheck() { 100 SpellCheck::~SpellCheck() {
30 } 101 }
31 102
32 bool SpellCheck::OnControlMessageReceived(const IPC::Message& message) { 103 bool SpellCheck::OnControlMessageReceived(const IPC::Message& message) {
33 bool handled = true; 104 bool handled = true;
34 IPC_BEGIN_MESSAGE_MAP(SpellCheck, message) 105 IPC_BEGIN_MESSAGE_MAP(SpellCheck, message)
35 IPC_MESSAGE_HANDLER(SpellCheckMsg_Init, OnInit) 106 IPC_MESSAGE_HANDLER(SpellCheckMsg_Init, OnInit)
36 IPC_MESSAGE_HANDLER(SpellCheckMsg_WordAdded, OnWordAdded) 107 IPC_MESSAGE_HANDLER(SpellCheckMsg_WordAdded, OnWordAdded)
37 IPC_MESSAGE_HANDLER(SpellCheckMsg_EnableAutoSpellCorrect, 108 IPC_MESSAGE_HANDLER(SpellCheckMsg_EnableAutoSpellCorrect,
38 OnEnableAutoSpellCorrect) 109 OnEnableAutoSpellCorrect)
39 IPC_MESSAGE_UNHANDLED(handled = false) 110 IPC_MESSAGE_UNHANDLED(handled = false)
40 IPC_END_MESSAGE_MAP() 111 IPC_END_MESSAGE_MAP()
41 112
42 return handled; 113 return handled;
43 } 114 }
44 115
45 void SpellCheck::OnInit(IPC::PlatformFileForTransit bdict_file, 116 void SpellCheck::OnInit(IPC::PlatformFileForTransit bdict_file,
46 const std::vector<std::string>& custom_words, 117 const std::vector<std::string>& custom_words,
47 const std::string& language, 118 const std::string& language,
48 bool auto_spell_correct) { 119 bool auto_spell_correct) {
49 Init(IPC::PlatformFileForTransitToPlatformFile(bdict_file), 120 Init(IPC::PlatformFileForTransitToPlatformFile(bdict_file),
50 custom_words, language); 121 custom_words, language);
51 auto_spell_correct_turned_on_ = auto_spell_correct; 122 auto_spell_correct_turned_on_ = auto_spell_correct;
123
124 PostDelayedSpellCheckTask();
52 } 125 }
53 126
54 void SpellCheck::OnWordAdded(const std::string& word) { 127 void SpellCheck::OnWordAdded(const std::string& word) {
55 if (is_using_platform_spelling_engine_) 128 if (is_using_platform_spelling_engine_)
56 return; 129 return;
57 130
58 if (!hunspell_.get()) { 131 if (!hunspell_.get()) {
59 // Save it for later---add it when hunspell is initialized. 132 // Save it for later---add it when hunspell is initialized.
60 custom_words_.push_back(word); 133 custom_words_.push_back(word);
61 } else { 134 } else {
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
140 if (optional_suggestions) 213 if (optional_suggestions)
141 FillSuggestionList(word, optional_suggestions); 214 FillSuggestionList(word, optional_suggestions);
142 return false; 215 return false;
143 } 216 }
144 217
145 return true; 218 return true;
146 } 219 }
147 220
148 bool SpellCheck::SpellCheckParagraph( 221 bool SpellCheck::SpellCheckParagraph(
149 const string16& text, 222 const string16& text,
150 int tag,
151 std::vector<SpellCheckResult>* results) { 223 std::vector<SpellCheckResult>* results) {
152 #if !defined(OS_MACOSX) 224 #if !defined(OS_MACOSX)
153 // Mac has its own spell checker, so this method will not be used. 225 // Mac has its own spell checker, so this method will not be used.
154 226
155 DCHECK(results); 227 DCHECK(results);
156 228
157 size_t length = text.length(); 229 size_t length = text.length();
158 size_t offset = 0; 230 size_t offset = 0;
159 231
160 // Spellcheck::SpellCheckWord() automatically breaks text into words and 232 // Spellcheck::SpellCheckWord() automatically breaks text into words and
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
231 break; 303 break;
232 } 304 }
233 } 305 }
234 306
235 // Restore the swapped characters. 307 // Restore the swapped characters.
236 std::swap(misspelled_word[i], misspelled_word[i + 1]); 308 std::swap(misspelled_word[i], misspelled_word[i + 1]);
237 } 309 }
238 return autocorrect_word; 310 return autocorrect_word;
239 } 311 }
240 312
313 void SpellCheck::RequestTextChecking(
314 const string16& text,
315 int offset,
316 WebKit::WebTextCheckingCompletion* completion) {
317 #if !defined(OS_MACOSX)
318 // Commented out on Mac, because SpellCheckRequest::PerformSpellCheck is not
319 // implemented on Mac. Mac uses its own spellchecker, so this method
320 // will not be used.
321
322 DCHECK(!is_using_platform_spelling_engine_);
323
324 // Clean up the previous request before starting a new request.
325 if (pending_request_param_.get()) {
326 pending_request_param_->completion()->didFinishCheckingText(
327 WebKit::WebVector<WebKit::WebTextCheckingResult>());
328 pending_request_param_ = NULL;
329 }
330
331 if (InitializeIfNeeded()) {
332 // We will check this text after we finish loading the hunspell dictionary.
333 // Save parameters so that we can use them when we receive an init message
334 // from the browser process.
335 pending_request_param_ = new SpellCheckRequestParam(
336 text, offset, completion);
337 return;
338 }
339
340 requested_params_.push(new SpellCheckRequestParam(text, offset, completion));
341 base::MessageLoopProxy::current()->PostTask(FROM_HERE,
342 base::Bind(&SpellCheck::PerformSpellCheck, AsWeakPtr()));
343 #else
344 NOTREACHED();
345 #endif
346 }
347
241 void SpellCheck::InitializeHunspell() { 348 void SpellCheck::InitializeHunspell() {
242 if (hunspell_.get()) 349 if (hunspell_.get())
243 return; 350 return;
244 351
245 bdict_file_.reset(new file_util::MemoryMappedFile); 352 bdict_file_.reset(new file_util::MemoryMappedFile);
246 353
247 if (bdict_file_->Initialize(file_)) { 354 if (bdict_file_->Initialize(file_)) {
248 TimeTicks debug_start_time = base::Histogram::DebugNow(); 355 TimeTicks debug_start_time = base::Histogram::DebugNow();
249 356
250 hunspell_.reset( 357 hunspell_.reset(
(...skipping 14 matching lines...) Expand all
265 372
266 void SpellCheck::AddWordToHunspell(const std::string& word) { 373 void SpellCheck::AddWordToHunspell(const std::string& word) {
267 if (!word.empty() && word.length() < MAXWORDUTF8LEN) 374 if (!word.empty() && word.length() < MAXWORDUTF8LEN)
268 hunspell_->add(word.c_str()); 375 hunspell_->add(word.c_str());
269 } 376 }
270 377
271 bool SpellCheck::InitializeIfNeeded() { 378 bool SpellCheck::InitializeIfNeeded() {
272 if (is_using_platform_spelling_engine_) 379 if (is_using_platform_spelling_engine_)
273 return false; 380 return false;
274 381
275 if (!initialized_) { 382 if (!initialized_ && !dictionary_requested_) {
276 RenderThread::Get()->Send(new SpellCheckHostMsg_RequestDictionary); 383 // RenderThread will not exist in test.
277 initialized_ = true; 384 if (RenderThread::Get())
385 RenderThread::Get()->Send(new SpellCheckHostMsg_RequestDictionary);
386 dictionary_requested_ = true;
278 return true; 387 return true;
279 } 388 }
280 389
281 // Don't initialize if hunspell is disabled. 390 // Don't initialize if hunspell is disabled.
282 if (file_ != base::kInvalidPlatformFileValue) 391 if (file_ != base::kInvalidPlatformFileValue)
283 InitializeHunspell(); 392 InitializeHunspell();
284 393
285 return false; 394 return !initialized_;
286 } 395 }
287 396
288 // When called, relays the request to check the spelling to the proper 397 // When called, relays the request to check the spelling to the proper
289 // backend, either hunspell or a platform-specific backend. 398 // backend, either hunspell or a platform-specific backend.
290 bool SpellCheck::CheckSpelling(const string16& word_to_check, int tag) { 399 bool SpellCheck::CheckSpelling(const string16& word_to_check, int tag) {
291 bool word_correct = false; 400 bool word_correct = false;
292 401
293 if (is_using_platform_spelling_engine_) { 402 if (is_using_platform_spelling_engine_) {
294 #if defined(OS_MACOSX) 403 #if defined(OS_MACOSX)
295 RenderThread::Get()->Send(new SpellCheckHostMsg_CheckSpelling( 404 RenderThread::Get()->Send(new SpellCheckHostMsg_CheckSpelling(
(...skipping 11 matching lines...) Expand all
307 // If |hunspell_| is NULL here, an error has occurred, but it's better 416 // If |hunspell_| is NULL here, an error has occurred, but it's better
308 // to check rather than crash. 417 // to check rather than crash.
309 word_correct = true; 418 word_correct = true;
310 } 419 }
311 } 420 }
312 } 421 }
313 422
314 return word_correct; 423 return word_correct;
315 } 424 }
316 425
426 void SpellCheck::PostDelayedSpellCheckTask() {
427 if (!pending_request_param_)
428 return;
429
430 if (file_ == base::kInvalidPlatformFileValue) {
431 pending_request_param_->completion()->didFinishCheckingText(
432 WebKit::WebVector<WebKit::WebTextCheckingResult>());
433 } else {
434 requested_params_.push(pending_request_param_);
435 base::MessageLoopProxy::current()->PostTask(FROM_HERE,
436 base::Bind(&SpellCheck::PerformSpellCheck, AsWeakPtr()));
437 }
438
439 pending_request_param_ = NULL;
440 }
441
442 void SpellCheck::PerformSpellCheck() {
443 #if !defined(OS_MACOSX)
444 DCHECK(!requested_params_.empty());
445 scoped_refptr<SpellCheckRequestParam> param = requested_params_.front();
446 DCHECK(param);
447 requested_params_.pop();
448
449 std::vector<SpellCheckResult> results;
450 SpellCheckParagraph(param->text(), &results);
451 param->completion()->didFinishCheckingText(
452 spellcheck::ToWebResultList(param->offset(), results));
453 #else
454 // SpellCheck::SpellCheckParagraph is not implemented on Mac,
455 // so we return without spellchecking. Note that Mac uses its own
456 // spellchecker, this function won't be used.
457 NOTREACHED();
458 #endif
459 }
460
317 void SpellCheck::FillSuggestionList( 461 void SpellCheck::FillSuggestionList(
318 const string16& wrong_word, 462 const string16& wrong_word,
319 std::vector<string16>* optional_suggestions) { 463 std::vector<string16>* optional_suggestions) {
320 if (is_using_platform_spelling_engine_) { 464 if (is_using_platform_spelling_engine_) {
321 #if defined(OS_MACOSX) 465 #if defined(OS_MACOSX)
322 RenderThread::Get()->Send(new SpellCheckHostMsg_FillSuggestionList( 466 RenderThread::Get()->Send(new SpellCheckHostMsg_FillSuggestionList(
323 wrong_word, optional_suggestions)); 467 wrong_word, optional_suggestions));
324 #endif 468 #endif
325 return; 469 return;
326 } 470 }
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
360 504
361 string16 word; 505 string16 word;
362 int word_start; 506 int word_start;
363 int word_length; 507 int word_length;
364 while (contraction_iterator_.GetNextWord(&word, &word_start, &word_length)) { 508 while (contraction_iterator_.GetNextWord(&word, &word_start, &word_length)) {
365 if (!CheckSpelling(word, tag)) 509 if (!CheckSpelling(word, tag))
366 return false; 510 return false;
367 } 511 }
368 return true; 512 return true;
369 } 513 }
OLDNEW
« no previous file with comments | « chrome/renderer/spellchecker/spellcheck.h ('k') | chrome/renderer/spellchecker/spellcheck_provider.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698