summaryrefslogtreecommitdiffstats
path: root/chrome/renderer
diff options
context:
space:
mode:
authorshinyak@chromium.org <shinyak@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-04-19 18:58:23 +0000
committershinyak@chromium.org <shinyak@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-04-19 18:58:23 +0000
commitacb38b0ab5acfa3327e57f2d2bed9d7626d0f2d0 (patch)
tree951b7f74260680369e9ec33d099de13488a4840b /chrome/renderer
parente4a1771c8d6de3e6eb60aa8ac159ad8e99403e06 (diff)
downloadchromium_src-acb38b0ab5acfa3327e57f2d2bed9d7626d0f2d0.zip
chromium_src-acb38b0ab5acfa3327e57f2d2bed9d7626d0f2d0.tar.gz
chromium_src-acb38b0ab5acfa3327e57f2d2bed9d7626d0f2d0.tar.bz2
This patch implements asynchronous spellchecker on Windows and Linux.
Though Mac already has its own spellchecker, Linux and Windows don't have one. So we have implemented asynchronous spellchecker posting a task. BUG=6424, 111593 TEST=SpellCheckTest.* Review URL: http://codereview.chromium.org/9169082 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@133029 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/renderer')
-rw-r--r--chrome/renderer/spellchecker/spellcheck.cc156
-rw-r--r--chrome/renderer/spellchecker/spellcheck.h62
-rw-r--r--chrome/renderer/spellchecker/spellcheck_provider.cc44
-rw-r--r--chrome/renderer/spellchecker/spellcheck_provider.h2
-rw-r--r--chrome/renderer/spellchecker/spellcheck_unittest.cc160
5 files changed, 382 insertions, 42 deletions
diff --git a/chrome/renderer/spellchecker/spellcheck.cc b/chrome/renderer/spellchecker/spellcheck.cc
index e8ccc1a..e16927a 100644
--- a/chrome/renderer/spellchecker/spellcheck.cc
+++ b/chrome/renderer/spellchecker/spellcheck.cc
@@ -4,8 +4,10 @@
#include "chrome/renderer/spellchecker/spellcheck.h"
+#include "base/bind.h"
#include "base/file_util.h"
#include "base/metrics/histogram.h"
+#include "base/message_loop_proxy.h"
#include "base/time.h"
#include "base/utf_string_conversions.h"
#include "chrome/common/render_messages.h"
@@ -14,15 +16,84 @@
#include "chrome/common/spellcheck_result.h"
#include "content/public/renderer/render_thread.h"
#include "third_party/hunspell/src/hunspell/hunspell.hxx"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebTextCheckingCompletion.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebTextCheckingResult.h"
using base::TimeTicks;
using content::RenderThread;
+using WebKit::WebVector;
+using WebKit::WebTextCheckingResult;
+using WebKit::WebTextCheckingType;
+
+namespace spellcheck {
+void ToWebResultList(
+ int offset,
+ const std::vector<SpellCheckResult>& results,
+ WebVector<WebTextCheckingResult>* web_results) {
+ WebVector<WebTextCheckingResult> list(results.size());
+ for (size_t i = 0; i < results.size(); ++i) {
+ list[i] = WebTextCheckingResult(
+ static_cast<WebTextCheckingType>(results[i].type),
+ results[i].location + offset,
+ results[i].length,
+ results[i].replacement);
+ }
+
+ list.swap(*web_results);
+}
+
+WebVector<WebTextCheckingResult> ToWebResultList(
+ int offset,
+ const std::vector<SpellCheckResult>& results) {
+ WebVector<WebTextCheckingResult> web_results;
+ ToWebResultList(offset, results, &web_results);
+ return web_results;
+}
+} // namespace spellcheck
+
+class SpellCheck::SpellCheckRequestParam
+ : public base::RefCountedThreadSafe<SpellCheck::SpellCheckRequestParam> {
+ public:
+ SpellCheckRequestParam(const string16& text,
+ int offset,
+ WebKit::WebTextCheckingCompletion* completion)
+ : text_(text),
+ offset_(offset),
+ completion_(completion) {
+ DCHECK(completion);
+ }
+
+ string16 text() {
+ return text_;
+ }
+
+ int offset() {
+ return offset_;
+ }
+
+ WebKit::WebTextCheckingCompletion* completion() {
+ return completion_;
+ }
+
+ private:
+ // Text to be checked in this task.
+ string16 text_;
+
+ // The text offset from the beginning.
+ int offset_;
+
+ // The interface to send the misspelled ranges to WebKit.
+ WebKit::WebTextCheckingCompletion* completion_;
+
+ DISALLOW_COPY_AND_ASSIGN(SpellCheckRequestParam);
+};
SpellCheck::SpellCheck()
: file_(base::kInvalidPlatformFileValue),
auto_spell_correct_turned_on_(false),
is_using_platform_spelling_engine_(false),
- initialized_(false) {
+ initialized_(false),
+ dictionary_requested_(false) {
// Wait till we check the first word before doing any initializing.
}
@@ -49,6 +120,8 @@ void SpellCheck::OnInit(IPC::PlatformFileForTransit bdict_file,
Init(IPC::PlatformFileForTransitToPlatformFile(bdict_file),
custom_words, language);
auto_spell_correct_turned_on_ = auto_spell_correct;
+
+ PostDelayedSpellCheckTask();
}
void SpellCheck::OnWordAdded(const std::string& word) {
@@ -147,7 +220,6 @@ bool SpellCheck::SpellCheckWord(
bool SpellCheck::SpellCheckParagraph(
const string16& text,
- int tag,
std::vector<SpellCheckResult>* results) {
#if !defined(OS_MACOSX)
// Mac has its own spell checker, so this method will not be used.
@@ -238,6 +310,41 @@ string16 SpellCheck::GetAutoCorrectionWord(const string16& word, int tag) {
return autocorrect_word;
}
+void SpellCheck::RequestTextChecking(
+ const string16& text,
+ int offset,
+ WebKit::WebTextCheckingCompletion* completion) {
+#if !defined(OS_MACOSX)
+ // Commented out on Mac, because SpellCheckRequest::PerformSpellCheck is not
+ // implemented on Mac. Mac uses its own spellchecker, so this method
+ // will not be used.
+
+ DCHECK(!is_using_platform_spelling_engine_);
+
+ // Clean up the previous request before starting a new request.
+ if (pending_request_param_.get()) {
+ pending_request_param_->completion()->didFinishCheckingText(
+ WebKit::WebVector<WebKit::WebTextCheckingResult>());
+ pending_request_param_ = NULL;
+ }
+
+ if (InitializeIfNeeded()) {
+ // We will check this text after we finish loading the hunspell dictionary.
+ // Save parameters so that we can use them when we receive an init message
+ // from the browser process.
+ pending_request_param_ = new SpellCheckRequestParam(
+ text, offset, completion);
+ return;
+ }
+
+ requested_params_.push(new SpellCheckRequestParam(text, offset, completion));
+ base::MessageLoopProxy::current()->PostTask(FROM_HERE,
+ base::Bind(&SpellCheck::PerformSpellCheck, AsWeakPtr()));
+#else
+ NOTREACHED();
+#endif
+}
+
void SpellCheck::InitializeHunspell() {
if (hunspell_.get())
return;
@@ -272,9 +379,11 @@ bool SpellCheck::InitializeIfNeeded() {
if (is_using_platform_spelling_engine_)
return false;
- if (!initialized_) {
- RenderThread::Get()->Send(new SpellCheckHostMsg_RequestDictionary);
- initialized_ = true;
+ if (!initialized_ && !dictionary_requested_) {
+ // RenderThread will not exist in test.
+ if (RenderThread::Get())
+ RenderThread::Get()->Send(new SpellCheckHostMsg_RequestDictionary);
+ dictionary_requested_ = true;
return true;
}
@@ -282,7 +391,7 @@ bool SpellCheck::InitializeIfNeeded() {
if (file_ != base::kInvalidPlatformFileValue)
InitializeHunspell();
- return false;
+ return !initialized_;
}
// When called, relays the request to check the spelling to the proper
@@ -314,6 +423,41 @@ bool SpellCheck::CheckSpelling(const string16& word_to_check, int tag) {
return word_correct;
}
+void SpellCheck::PostDelayedSpellCheckTask() {
+ if (!pending_request_param_)
+ return;
+
+ if (file_ == base::kInvalidPlatformFileValue) {
+ pending_request_param_->completion()->didFinishCheckingText(
+ WebKit::WebVector<WebKit::WebTextCheckingResult>());
+ } else {
+ requested_params_.push(pending_request_param_);
+ base::MessageLoopProxy::current()->PostTask(FROM_HERE,
+ base::Bind(&SpellCheck::PerformSpellCheck, AsWeakPtr()));
+ }
+
+ pending_request_param_ = NULL;
+}
+
+void SpellCheck::PerformSpellCheck() {
+#if !defined(OS_MACOSX)
+ DCHECK(!requested_params_.empty());
+ scoped_refptr<SpellCheckRequestParam> param = requested_params_.front();
+ DCHECK(param);
+ requested_params_.pop();
+
+ std::vector<SpellCheckResult> results;
+ SpellCheckParagraph(param->text(), &results);
+ param->completion()->didFinishCheckingText(
+ spellcheck::ToWebResultList(param->offset(), results));
+#else
+ // SpellCheck::SpellCheckParagraph is not implemented on Mac,
+ // so we return without spellchecking. Note that Mac uses its own
+ // spellchecker, this function won't be used.
+ NOTREACHED();
+#endif
+}
+
void SpellCheck::FillSuggestionList(
const string16& wrong_word,
std::vector<string16>* optional_suggestions) {
diff --git a/chrome/renderer/spellchecker/spellcheck.h b/chrome/renderer/spellchecker/spellcheck.h
index 8567163..5cf0ef4 100644
--- a/chrome/renderer/spellchecker/spellcheck.h
+++ b/chrome/renderer/spellchecker/spellcheck.h
@@ -7,16 +7,20 @@
#pragma once
#include <string>
+#include <queue>
#include <vector>
#include "base/gtest_prod_util.h"
+#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
#include "base/platform_file.h"
#include "base/string16.h"
#include "base/time.h"
#include "chrome/renderer/spellchecker/spellcheck_worditerator.h"
#include "content/public/renderer/render_process_observer.h"
#include "ipc/ipc_platform_file.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebVector.h"
#include "unicode/uscript.h"
class Hunspell;
@@ -26,9 +30,28 @@ namespace file_util {
class MemoryMappedFile;
}
+namespace WebKit {
+class WebTextCheckingCompletion;
+struct WebTextCheckingResult;
+}
+
+namespace spellcheck {
+// Converts vector<SpellCheckResult> to WebVector<WebTextCheckingResult>
+// for WebKit.
+void ToWebResultList(
+ int offset,
+ const std::vector<SpellCheckResult>& results,
+ WebKit::WebVector<WebKit::WebTextCheckingResult>* web_results);
+
+WebKit::WebVector<WebKit::WebTextCheckingResult> ToWebResultList(
+ int offset,
+ const std::vector<SpellCheckResult>& results);
+}
+
// TODO(morrita): Needs reorg with SpellCheckProvider.
// See http://crbug.com/73699.
-class SpellCheck : public content::RenderProcessObserver {
+class SpellCheck : public content::RenderProcessObserver,
+ public base::SupportsWeakPtr<SpellCheck> {
public:
SpellCheck();
virtual ~SpellCheck();
@@ -57,10 +80,7 @@ class SpellCheck : public content::RenderProcessObserver {
// SpellCheck a paragrpah.
// Returns true if |text| is correctly spelled, false otherwise.
// If the spellchecker failed to initialize, always returns true.
- // The |tag| parameter should either be a unique identifier for the document,
- // or 0.
bool SpellCheckParagraph(const string16& text,
- int tag,
std::vector<SpellCheckResult>* results);
// Find a possible correctly spelled word for a misspelled word. Computes an
@@ -71,6 +91,12 @@ class SpellCheck : public content::RenderProcessObserver {
// behind its command line flag.
string16 GetAutoCorrectionWord(const string16& word, int tag);
+ // Requests to spellcheck the specified text in the background. This function
+ // posts a background task and calls SpellCheckParagraph() in the task.
+ void RequestTextChecking(const string16& text,
+ int offset,
+ WebKit::WebTextCheckingCompletion* completion);
+
// Returns true if the spellchecker delegate checking to a system-provided
// checker on the browser process.
bool is_using_platform_spelling_engine() const {
@@ -79,6 +105,10 @@ class SpellCheck : public content::RenderProcessObserver {
private:
FRIEND_TEST_ALL_PREFIXES(SpellCheckTest, GetAutoCorrectionWord_EN_US);
+ FRIEND_TEST_ALL_PREFIXES(SpellCheckTest,
+ RequestSpellCheckMultipleTimesWithoutInitialization);
+
+ class SpellCheckRequestParam;
// RenderProcessObserver implementation:
virtual bool OnControlMessageReceived(const IPC::Message& message) OVERRIDE;
@@ -107,6 +137,12 @@ class SpellCheck : public content::RenderProcessObserver {
// backend, either hunspell or a platform-specific backend.
bool CheckSpelling(const string16& word_to_check, int tag);
+ // Posts delayed spellcheck task and clear it if any.
+ void PostDelayedSpellCheckTask();
+
+ // Performs spell checking from the request queue.
+ void PerformSpellCheck();
+
// When called, relays the request to fill the list with suggestions to
// the proper backend, either hunspell or a platform-specific backend.
void FillSuggestionList(const string16& wrong_word,
@@ -147,12 +183,26 @@ class SpellCheck : public content::RenderProcessObserver {
// and False if hunspell is being used.
bool is_using_platform_spelling_engine_;
- // This flags whether we have ever been initialized, or have asked the browser
- // for a dictionary. The value indicates whether we should request a
+ // This flags is true if we have been intialized.
+ // The value indicates whether we should request a
// dictionary from the browser when the render view asks us to check the
// spelling of a word.
bool initialized_;
+ // This flags is true if we have requested dictionary.
+ bool dictionary_requested_;
+
+ // The parameters of a pending background-spellchecking request. When WebKit
+ // sends a background-spellchecking request before initializing hunspell,
+ // we save its parameters and start spellchecking after we finish initializing
+ // hunspell. (When WebKit sends two or more requests, we cancel the previous
+ // requests so we do not have to use vectors.)
+ scoped_refptr<SpellCheckRequestParam> pending_request_param_;
+
+ // The set of params already requested. When finishing the request, the params
+ // should be removed from the set.
+ std::queue<scoped_refptr<SpellCheckRequestParam> > requested_params_;
+
DISALLOW_COPY_AND_ASSIGN(SpellCheck);
};
diff --git a/chrome/renderer/spellchecker/spellcheck_provider.cc b/chrome/renderer/spellchecker/spellcheck_provider.cc
index 89b7cfc..b3fd4a9 100644
--- a/chrome/renderer/spellchecker/spellcheck_provider.cc
+++ b/chrome/renderer/spellchecker/spellcheck_provider.cc
@@ -18,6 +18,7 @@
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebVector.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
+using spellcheck::ToWebResultList;
using WebKit::WebFrame;
using WebKit::WebString;
using WebKit::WebTextCheckingCompletion;
@@ -42,34 +43,6 @@ COMPILE_ASSERT(int(WebKit::WebTextCheckingTypeCorrection) ==
COMPILE_ASSERT(int(WebKit::WebTextCheckingTypeShowCorrectionPanel) ==
int(SpellCheckResult::SHOWCORRECTIONPANEL), mismatching_enums);
-namespace {
-
-void ToWebResultList(
- int offset,
- const std::vector<SpellCheckResult>& results,
- WebVector<WebTextCheckingResult>* web_results) {
- WebVector<WebTextCheckingResult> list(results.size());
- for (size_t i = 0; i < results.size(); ++i) {
- list[i] = WebTextCheckingResult(
- static_cast<WebTextCheckingType>(results[i].type),
- results[i].location + offset,
- results[i].length,
- results[i].replacement);
- }
-
- list.swap(*web_results);
-}
-
-WebVector<WebTextCheckingResult> ToWebResultList(
- int offset,
- const std::vector<SpellCheckResult>& results) {
- WebVector<WebTextCheckingResult> web_results;
- ToWebResultList(offset, results, &web_results);
- return web_results;
-}
-
-} // namespace
-
SpellCheckProvider::SpellCheckProvider(
content::RenderView* render_view,
chrome::ChromeContentRendererClient* renderer_client)
@@ -118,6 +91,7 @@ void SpellCheckProvider::RequestTextChecking(
completion->didFinishCheckingText(std::vector<WebTextCheckingResult>());
return;
}
+
last_line_ = line;
Send(new SpellCheckHostMsg_CallSpellingService(
routing_id(),
@@ -210,7 +184,6 @@ void SpellCheckProvider::checkTextOfParagraph(
std::vector<SpellCheckResult> tmp_results;
chrome_content_renderer_client_->spellcheck()->SpellCheckParagraph(
string16(text),
- document_tag_,
&tmp_results);
ToWebResultList(0, tmp_results, results);
#endif
@@ -257,12 +230,25 @@ void SpellCheckProvider::updateSpellingUIWithMisspelledWord(
void SpellCheckProvider::OnRespondSpellingService(
int identifier,
int offset,
+ bool succeeded,
+ const string16& text,
const std::vector<SpellCheckResult>& results) {
WebTextCheckingCompletion* completion =
text_check_completions_.Lookup(identifier);
if (!completion)
return;
text_check_completions_.Remove(identifier);
+
+ // If |succeeded| is false, we use local spellcheck as a fallback.
+ if (!succeeded) {
+ // |chrome_content_renderer_client| may be NULL in unit tests.
+ if (chrome_content_renderer_client_) {
+ chrome_content_renderer_client_->spellcheck()->RequestTextChecking(
+ text, offset, completion);
+ return;
+ }
+ }
+
completion->didFinishCheckingText(ToWebResultList(offset, results));
}
diff --git a/chrome/renderer/spellchecker/spellcheck_provider.h b/chrome/renderer/spellchecker/spellcheck_provider.h
index 72ac84e..8419c90 100644
--- a/chrome/renderer/spellchecker/spellcheck_provider.h
+++ b/chrome/renderer/spellchecker/spellcheck_provider.h
@@ -81,6 +81,8 @@ class SpellCheckProvider : public content::RenderViewObserver,
void OnRespondSpellingService(
int identifier,
int offset,
+ bool succeeded,
+ const string16& text,
const std::vector<SpellCheckResult>& results);
// Returns whether |text| has word characters after |index|, i.e. whether a
diff --git a/chrome/renderer/spellchecker/spellcheck_unittest.cc b/chrome/renderer/spellchecker/spellcheck_unittest.cc
index eeb0a4d..4e2cea6 100644
--- a/chrome/renderer/spellchecker/spellcheck_unittest.cc
+++ b/chrome/renderer/spellchecker/spellcheck_unittest.cc
@@ -15,6 +15,8 @@
#include "chrome/common/spellcheck_common.h"
#include "chrome/common/spellcheck_result.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebTextCheckingCompletion.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebTextCheckingResult.h"
namespace {
@@ -39,7 +41,14 @@ class SpellCheckTest : public testing::Test {
void ReinitializeSpellCheck(const std::string& language) {
spell_check_.reset(new SpellCheck());
+ InitializeSpellCheck(language);
+ }
+
+ void UninitializeSpellCheck() {
+ spell_check_.reset(new SpellCheck());
+ }
+ void InitializeSpellCheck(const std::string& language) {
FilePath hunspell_directory = GetHunspellDirectory();
EXPECT_FALSE(hunspell_directory.empty());
base::PlatformFile file = base::CreatePlatformFile(
@@ -61,7 +70,6 @@ class SpellCheckTest : public testing::Test {
const std::vector<SpellCheckResult>& expected) {
std::vector<SpellCheckResult> results;
spell_check()->SpellCheckParagraph(input,
- 0,
&results);
EXPECT_EQ(results.size(), expected.size());
@@ -76,6 +84,24 @@ class SpellCheckTest : public testing::Test {
private:
scoped_ptr<SpellCheck> spell_check_;
+ MessageLoop loop;
+};
+
+// A fake completion object for verification.
+class MockTextCheckingCompletion : public WebKit::WebTextCheckingCompletion {
+ public:
+ MockTextCheckingCompletion()
+ : completion_count_(0) {
+ }
+
+ virtual void didFinishCheckingText(
+ const WebKit::WebVector<WebKit::WebTextCheckingResult>& results) {
+ completion_count_++;
+ last_results_ = results;
+ }
+
+ size_t completion_count_;
+ WebKit::WebVector<WebKit::WebTextCheckingResult> last_results_;
};
// Operates unit tests for the webkit_glue::SpellCheckWord() function
@@ -808,4 +834,136 @@ TEST_F(SpellCheckTest, SpellCheckParagraphLongSentenceMultipleMisspellings) {
TestSpellCheckParagraph(text, expected);
}
+
+// We also skip RequestSpellCheck tests on Mac, because a system spellchecker
+// is used on Mac instead of SpellCheck::RequestTextChecking.
+
+// Make sure RequestTextChecking does not crash if input is empty.
+TEST_F(SpellCheckTest, RequestSpellCheckWithEmptyString) {
+ MockTextCheckingCompletion completion;
+
+ const string16 text = ASCIIToUTF16("");
+ spell_check()->RequestTextChecking(text, 0, &completion);
+
+ MessageLoop::current()->RunAllPending();
+
+ EXPECT_EQ(completion.completion_count_, 1U);
+}
+
+// A simple test case having no misspellings.
+TEST_F(SpellCheckTest, RequestSpellCheckWithoutMisspelling) {
+ MockTextCheckingCompletion completion;
+
+ const string16 text = ASCIIToUTF16("hello");
+ spell_check()->RequestTextChecking(text, 0, &completion);
+
+ MessageLoop::current()->RunAllPending();
+
+ EXPECT_EQ(completion.completion_count_, 1U);
+}
+
+// A simple test case having one misspelling.
+TEST_F(SpellCheckTest, RequestSpellCheckWithSingleMisspelling) {
+ MockTextCheckingCompletion completion;
+
+ const string16 text = ASCIIToUTF16("apple, zz");
+ spell_check()->RequestTextChecking(text, 0, &completion);
+
+ MessageLoop::current()->RunAllPending();
+
+ EXPECT_EQ(completion.completion_count_, 1U);
+ EXPECT_EQ(completion.last_results_.size(), 1U);
+ EXPECT_EQ(completion.last_results_[0].location, 7);
+ EXPECT_EQ(completion.last_results_[0].length, 2);
+}
+
+// A simple test case having a few misspellings.
+TEST_F(SpellCheckTest, RequestSpellCheckWithMisspellings) {
+ MockTextCheckingCompletion completion;
+
+ const string16 text = ASCIIToUTF16("apple, zz, orange, zz");
+ spell_check()->RequestTextChecking(text, 0, &completion);
+
+ MessageLoop::current()->RunAllPending();
+
+ EXPECT_EQ(completion.completion_count_, 1U);
+ EXPECT_EQ(completion.last_results_.size(), 2U);
+ EXPECT_EQ(completion.last_results_[0].location, 7);
+ EXPECT_EQ(completion.last_results_[0].length, 2);
+ EXPECT_EQ(completion.last_results_[1].location, 19);
+ EXPECT_EQ(completion.last_results_[1].length, 2);
+}
+
+// A test case that multiple requests comes at once. Make sure all
+// requests are processed.
+TEST_F(SpellCheckTest, RequestSpellCheckWithMultipleRequests) {
+ MockTextCheckingCompletion completion[3];
+
+ const string16 text[3] = {
+ ASCIIToUTF16("what, zz"),
+ ASCIIToUTF16("apple, zz"),
+ ASCIIToUTF16("orange, zz")
+ };
+
+ for (int i = 0; i < 3; ++i)
+ spell_check()->RequestTextChecking(text[i], 0, &completion[i]);
+
+ MessageLoop::current()->RunAllPending();
+
+ for (int i = 0; i < 3; ++i) {
+ EXPECT_EQ(completion[i].completion_count_, 1U);
+ EXPECT_EQ(completion[i].last_results_.size(), 1U);
+ EXPECT_EQ(completion[i].last_results_[0].location, 6 + i);
+ EXPECT_EQ(completion[i].last_results_[0].length, 2);
+ }
+}
+
+// A test case that spellchecking is requested before initializing.
+// In this case, we postpone to post a request.
+TEST_F(SpellCheckTest, RequestSpellCheckWithoutInitialization) {
+ UninitializeSpellCheck();
+
+ MockTextCheckingCompletion completion;
+ const string16 text = ASCIIToUTF16("zz");
+
+ spell_check()->RequestTextChecking(text, 0, &completion);
+
+ // The task will not be posted yet.
+ MessageLoop::current()->RunAllPending();
+ EXPECT_EQ(completion.completion_count_, 0U);
+}
+
+// Requests several spellchecking before initializing. Except the last one,
+// posting requests is cancelled and text is rendered as correct one.
+TEST_F(SpellCheckTest, RequestSpellCheckMultipleTimesWithoutInitialization) {
+ UninitializeSpellCheck();
+
+ MockTextCheckingCompletion completion[3];
+ const string16 text[3] = {
+ ASCIIToUTF16("what, zz"),
+ ASCIIToUTF16("apple, zz"),
+ ASCIIToUTF16("orange, zz")
+ };
+
+ // Calls RequestTextchecking a few times.
+ for (int i = 0; i < 3; ++i)
+ spell_check()->RequestTextChecking(text[i], 0, &completion[i]);
+
+ // The last task will be posted after initialization, however the other
+ // requests should be pressed without spellchecking.
+ MessageLoop::current()->RunAllPending();
+ for (int i = 0; i < 2; ++i)
+ EXPECT_EQ(completion[i].completion_count_, 1U);
+ EXPECT_EQ(completion[2].completion_count_, 0U);
+
+ // Checks the last request is processed after initialization.
+ InitializeSpellCheck("en-US");
+
+ // Calls PostDelayedSpellCheckTask instead of OnInit here for simplicity.
+ spell_check()->PostDelayedSpellCheckTask();
+ MessageLoop::current()->RunAllPending();
+ for (int i = 0; i < 3; ++i)
+ EXPECT_EQ(completion[i].completion_count_, 1U);
+}
+
#endif