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

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: Created 8 years, 10 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.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 "content/public/renderer/render_thread.h" 16 #include "content/public/renderer/render_thread.h"
15 #include "third_party/hunspell/src/hunspell/hunspell.hxx" 17 #include "third_party/hunspell/src/hunspell/hunspell.hxx"
18 #include "third_party/WebKit/Source/WebKit/chromium/public/WebTextCheckingComple tion.h"
16 #include "third_party/WebKit/Source/WebKit/chromium/public/WebTextCheckingResult .h" 19 #include "third_party/WebKit/Source/WebKit/chromium/public/WebTextCheckingResult .h"
20 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebVector.h"
17 21
18 using base::TimeTicks; 22 using base::TimeTicks;
19 using content::RenderThread; 23 using content::RenderThread;
20 24
25 // A request that checks the spellings of the specified text.
26 class SpellCheck::SpellCheckRequest
27 : public base::RefCountedThreadSafe<SpellCheck::SpellCheckRequest> {
Hironori Bono 2012/01/27 06:17:41 I do not think we need a new class for this use-ca
shinyak 2012/01/30 06:53:05 Actually |text| is a temporary object, so the refe
28 public:
29 SpellCheckRequest(const string16& text,
30 int tag,
31 WebKit::WebTextCheckingCompletion* completion,
32 SpellCheck* spellcheck)
33 : text_(text),
34 tag_(tag),
35 completion_(completion),
36 spellcheck_(spellcheck) {
37 DCHECK(completion);
38 DCHECK(spellcheck);
39 }
40
41 // Performs spellchecking and calls the callback function.
42 void PerformSpellCheck() {
43 #if !defined(OS_MACOSX)
44 std::vector<WebKit::WebTextCheckingResult> results;
45 spellcheck_->SpellCheckParagraph(text_, tag_, &results);
Hironori Bono 2012/01/27 06:17:41 This call surely creates confusing crashes when a
shinyak 2012/01/30 06:53:05 Done.
46 completion_->didFinishCheckingText(results);
47 #else
48 // SpellCheck::SpellCheckParagraph is not implemented on Mac,
49 // so we return without spellchecking. Note that Mac uses its own
50 // spellchecker, this function won't be used.
Hironori Bono 2012/01/27 06:17:41 Use NOTREACHED() and let a renderer crash when som
shinyak 2012/01/30 06:53:05 Done.
51 completion_->didFinishCheckingText(
52 WebKit::WebVector<WebKit::WebTextCheckingResult>());
53 #endif
54 }
55
56 // Calls the callback function without doing spellchecking.
57 // Text is considered as having no misspellings.
58 void CancelSpellCheckRequest() {
59 completion_->didFinishCheckingText(
60 WebKit::WebVector<WebKit::WebTextCheckingResult>());
61 }
62
63 private:
64 friend class base::RefCountedThreadSafe<SpellCheckRequest>;
65
66 ~SpellCheckRequest() {
67 }
68
69 // Text to be checked in this task.
70 string16 text_;
71
72 // The document tag provided by WebKit.
73 int tag_;
74
75 // The interface to send the misspelled ranges to WebKit.
76 WebKit::WebTextCheckingCompletion* completion_;
77
78 // The spellchecker shared in this process.
79 SpellCheck* spellcheck_;
80 };
81
21 SpellCheck::SpellCheck() 82 SpellCheck::SpellCheck()
22 : file_(base::kInvalidPlatformFileValue), 83 : file_(base::kInvalidPlatformFileValue),
23 auto_spell_correct_turned_on_(false), 84 auto_spell_correct_turned_on_(false),
24 is_using_platform_spelling_engine_(false), 85 is_using_platform_spelling_engine_(false),
25 initialized_(false) { 86 initialized_(false),
87 dictionary_requested_(false) {
26 // Wait till we check the first word before doing any initializing. 88 // Wait till we check the first word before doing any initializing.
27 } 89 }
28 90
29 SpellCheck::~SpellCheck() { 91 SpellCheck::~SpellCheck() {
30 } 92 }
31 93
32 bool SpellCheck::OnControlMessageReceived(const IPC::Message& message) { 94 bool SpellCheck::OnControlMessageReceived(const IPC::Message& message) {
33 bool handled = true; 95 bool handled = true;
34 IPC_BEGIN_MESSAGE_MAP(SpellCheck, message) 96 IPC_BEGIN_MESSAGE_MAP(SpellCheck, message)
35 IPC_MESSAGE_HANDLER(SpellCheckMsg_Init, OnInit) 97 IPC_MESSAGE_HANDLER(SpellCheckMsg_Init, OnInit)
36 IPC_MESSAGE_HANDLER(SpellCheckMsg_WordAdded, OnWordAdded) 98 IPC_MESSAGE_HANDLER(SpellCheckMsg_WordAdded, OnWordAdded)
37 IPC_MESSAGE_HANDLER(SpellCheckMsg_EnableAutoSpellCorrect, 99 IPC_MESSAGE_HANDLER(SpellCheckMsg_EnableAutoSpellCorrect,
38 OnEnableAutoSpellCorrect) 100 OnEnableAutoSpellCorrect)
39 IPC_MESSAGE_UNHANDLED(handled = false) 101 IPC_MESSAGE_UNHANDLED(handled = false)
40 IPC_END_MESSAGE_MAP() 102 IPC_END_MESSAGE_MAP()
41 103
42 return handled; 104 return handled;
43 } 105 }
44 106
45 void SpellCheck::OnInit(IPC::PlatformFileForTransit bdict_file, 107 void SpellCheck::OnInit(IPC::PlatformFileForTransit bdict_file,
46 const std::vector<std::string>& custom_words, 108 const std::vector<std::string>& custom_words,
47 const std::string& language, 109 const std::string& language,
48 bool auto_spell_correct) { 110 bool auto_spell_correct) {
49 Init(IPC::PlatformFileForTransitToPlatformFile(bdict_file), 111 Init(IPC::PlatformFileForTransitToPlatformFile(bdict_file),
50 custom_words, language); 112 custom_words, language);
51 auto_spell_correct_turned_on_ = auto_spell_correct; 113 auto_spell_correct_turned_on_ = auto_spell_correct;
114
115 PostDelayedSpellCheckTask();
52 } 116 }
53 117
54 void SpellCheck::OnWordAdded(const std::string& word) { 118 void SpellCheck::OnWordAdded(const std::string& word) {
55 if (is_using_platform_spelling_engine_) 119 if (is_using_platform_spelling_engine_)
56 return; 120 return;
57 121
58 if (!hunspell_.get()) { 122 if (!hunspell_.get()) {
59 // Save it for later---add it when hunspell is initialized. 123 // Save it for later---add it when hunspell is initialized.
60 custom_words_.push_back(word); 124 custom_words_.push_back(word);
61 } else { 125 } else {
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after
231 break; 295 break;
232 } 296 }
233 } 297 }
234 298
235 // Restore the swapped characters. 299 // Restore the swapped characters.
236 std::swap(misspelled_word[i], misspelled_word[i + 1]); 300 std::swap(misspelled_word[i], misspelled_word[i + 1]);
237 } 301 }
238 return autocorrect_word; 302 return autocorrect_word;
239 } 303 }
240 304
305 void SpellCheck::RequestTextChecking(
306 const string16& text,
307 int tag,
308 WebKit::WebTextCheckingCompletion* completion) {
309 #if !defined(OS_MACOSX)
310 // Commented out on Mac, because SpellCheckRequest::PerformSpellCheck is not
311 // implemented on Mac. Mac uses its own spellchecker, so this method
312 // will not be used.
313
314 DCHECK(!is_using_platform_spelling_engine_);
315
316 // Clean up the previous request before starting a new request.
317 if (pending_request_) {
318 pending_request_->CancelSpellCheckRequest();
319 pending_request_ = NULL;
320 }
321
322 if (InitializeIfNeeded()) {
323 // We will check this text after we finish loading the hunspell dictionary.
324 // Save parameters so that we can use them when we receive an init message
325 // from the browser process.
326 pending_request_ = new SpellCheckRequest(text, tag, completion, this);
327 return;
328 }
329
330 scoped_refptr<SpellCheckRequest> request(
331 new SpellCheckRequest(text, tag, completion, this));
332 MessageLoop::current()->PostTask(FROM_HERE,
333 base::Bind(&SpellCheckRequest::PerformSpellCheck, request));
334 #endif
335 }
336
241 void SpellCheck::InitializeHunspell() { 337 void SpellCheck::InitializeHunspell() {
242 if (hunspell_.get()) 338 if (hunspell_.get())
243 return; 339 return;
244 340
245 bdict_file_.reset(new file_util::MemoryMappedFile); 341 bdict_file_.reset(new file_util::MemoryMappedFile);
246 342
247 if (bdict_file_->Initialize(file_)) { 343 if (bdict_file_->Initialize(file_)) {
248 TimeTicks debug_start_time = base::Histogram::DebugNow(); 344 TimeTicks debug_start_time = base::Histogram::DebugNow();
249 345
250 hunspell_.reset( 346 hunspell_.reset(
(...skipping 14 matching lines...) Expand all
265 361
266 void SpellCheck::AddWordToHunspell(const std::string& word) { 362 void SpellCheck::AddWordToHunspell(const std::string& word) {
267 if (!word.empty() && word.length() < MAXWORDUTF8LEN) 363 if (!word.empty() && word.length() < MAXWORDUTF8LEN)
268 hunspell_->add(word.c_str()); 364 hunspell_->add(word.c_str());
269 } 365 }
270 366
271 bool SpellCheck::InitializeIfNeeded() { 367 bool SpellCheck::InitializeIfNeeded() {
272 if (is_using_platform_spelling_engine_) 368 if (is_using_platform_spelling_engine_)
273 return false; 369 return false;
274 370
275 if (!initialized_) { 371 if (!initialized_ && !dictionary_requested_) {
276 RenderThread::Get()->Send(new SpellCheckHostMsg_RequestDictionary); 372 // RenderThread will not exist in test.
277 initialized_ = true; 373 if (RenderThread::Get())
374 RenderThread::Get()->Send(new SpellCheckHostMsg_RequestDictionary);
375 dictionary_requested_ = true;
278 return true; 376 return true;
279 } 377 }
280 378
281 // Don't initialize if hunspell is disabled. 379 // Don't initialize if hunspell is disabled.
282 if (file_ != base::kInvalidPlatformFileValue) 380 if (file_ != base::kInvalidPlatformFileValue)
283 InitializeHunspell(); 381 InitializeHunspell();
284 382
285 return false; 383 return !initialized_;
286 } 384 }
287 385
288 // When called, relays the request to check the spelling to the proper 386 // When called, relays the request to check the spelling to the proper
289 // backend, either hunspell or a platform-specific backend. 387 // backend, either hunspell or a platform-specific backend.
290 bool SpellCheck::CheckSpelling(const string16& word_to_check, int tag) { 388 bool SpellCheck::CheckSpelling(const string16& word_to_check, int tag) {
291 bool word_correct = false; 389 bool word_correct = false;
292 390
293 if (is_using_platform_spelling_engine_) { 391 if (is_using_platform_spelling_engine_) {
294 #if defined(OS_MACOSX) 392 #if defined(OS_MACOSX)
295 RenderThread::Get()->Send(new SpellCheckHostMsg_CheckSpelling( 393 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 405 // If |hunspell_| is NULL here, an error has occurred, but it's better
308 // to check rather than crash. 406 // to check rather than crash.
309 word_correct = true; 407 word_correct = true;
310 } 408 }
311 } 409 }
312 } 410 }
313 411
314 return word_correct; 412 return word_correct;
315 } 413 }
316 414
415 void SpellCheck::PostDelayedSpellCheckTask() {
416 if (!pending_request_)
417 return;
418
419 if (file_ == base::kInvalidPlatformFileValue) {
420 pending_request_->CancelSpellCheckRequest();
421 } else {
422 MessageLoop::current()->PostTask(FROM_HERE,
Hironori Bono 2012/01/27 06:17:41 This is an old way to post a task. (This code cras
shinyak 2012/01/30 06:53:05 Done.
423 base::Bind(&SpellCheckRequest::PerformSpellCheck, pending_request_));
424 }
425
426 pending_request_ = NULL;
427 }
428
317 void SpellCheck::FillSuggestionList( 429 void SpellCheck::FillSuggestionList(
318 const string16& wrong_word, 430 const string16& wrong_word,
319 std::vector<string16>* optional_suggestions) { 431 std::vector<string16>* optional_suggestions) {
320 if (is_using_platform_spelling_engine_) { 432 if (is_using_platform_spelling_engine_) {
321 #if defined(OS_MACOSX) 433 #if defined(OS_MACOSX)
322 RenderThread::Get()->Send(new SpellCheckHostMsg_FillSuggestionList( 434 RenderThread::Get()->Send(new SpellCheckHostMsg_FillSuggestionList(
323 wrong_word, optional_suggestions)); 435 wrong_word, optional_suggestions));
324 #endif 436 #endif
325 return; 437 return;
326 } 438 }
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
360 472
361 string16 word; 473 string16 word;
362 int word_start; 474 int word_start;
363 int word_length; 475 int word_length;
364 while (contraction_iterator_.GetNextWord(&word, &word_start, &word_length)) { 476 while (contraction_iterator_.GetNextWord(&word, &word_start, &word_length)) {
365 if (!CheckSpelling(word, tag)) 477 if (!CheckSpelling(word, tag))
366 return false; 478 return false;
367 } 479 }
368 return true; 480 return true;
369 } 481 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698