diff options
23 files changed, 666 insertions, 3 deletions
diff --git a/chrome/browser/renderer_host/browser_render_process_host.cc b/chrome/browser/renderer_host/browser_render_process_host.cc index be7cc29..f776ac1 100644 --- a/chrome/browser/renderer_host/browser_render_process_host.cc +++ b/chrome/browser/renderer_host/browser_render_process_host.cc @@ -69,6 +69,7 @@ #include "chrome/browser/speech/speech_input_dispatcher_host.h" #include "chrome/browser/speech/speech_input_manager.h" #include "chrome/browser/spellcheck_host.h" +#include "chrome/browser/spellcheck_message_filter.h" #include "chrome/browser/metrics/user_metrics.h" #include "chrome/browser/visitedlink/visitedlink_master.h" #include "chrome/browser/worker_host/worker_message_filter.h" @@ -475,6 +476,7 @@ void BrowserRenderProcessHost::CreateMessageFilters() { url_request_context_override); channel_->AddFilter(socket_stream_dispatcher_host); + channel_->AddFilter(new SpellCheckMessageFilter()); channel_->AddFilter(new WorkerMessageFilter( id(), profile()->GetRequestContext(), diff --git a/chrome/browser/spellcheck_message_filter.cc b/chrome/browser/spellcheck_message_filter.cc new file mode 100644 index 0000000..f2efbf9 --- /dev/null +++ b/chrome/browser/spellcheck_message_filter.cc @@ -0,0 +1,34 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/spellcheck_message_filter.h" + +#include "chrome/browser/spellchecker_platform_engine.h" +#include "chrome/common/render_messages.h" + +SpellCheckMessageFilter::SpellCheckMessageFilter() { +} + +SpellCheckMessageFilter::~SpellCheckMessageFilter() { +} + +bool SpellCheckMessageFilter::OnMessageReceived(const IPC::Message& message, + bool* message_was_ok) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP_EX(SpellCheckMessageFilter, message, *message_was_ok) + IPC_MESSAGE_HANDLER(ViewHostMsg_SpellChecker_PlatformRequestTextCheck, + OnPlatformRequestTextCheck) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void SpellCheckMessageFilter::OnPlatformRequestTextCheck( + int route_id, + int identifier, + int document_tag, + const string16& text) { + SpellCheckerPlatform::RequestTextCheck( + route_id, identifier, document_tag, text, this); +} diff --git a/chrome/browser/spellcheck_message_filter.h b/chrome/browser/spellcheck_message_filter.h new file mode 100644 index 0000000..d20ff3c --- /dev/null +++ b/chrome/browser/spellcheck_message_filter.h @@ -0,0 +1,28 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_SPELLCHECK_MESSAGE_FILTER_H_ +#define CHROME_BROWSER_SPELLCHECK_MESSAGE_FILTER_H_ + +#include "chrome/browser/browser_message_filter.h" + +// A message filter implementation that receives +// the platform spell checker requests from SpellCheckProvider. +class SpellCheckMessageFilter : public BrowserMessageFilter { + public: + SpellCheckMessageFilter(); + ~SpellCheckMessageFilter(); + + // BrowserMessageFilter implementation. + virtual bool OnMessageReceived(const IPC::Message& message, + bool* message_was_ok); + + private: + void OnPlatformRequestTextCheck(int route_id, + int identifier, + int document_tag, + const string16& text); +}; + +#endif // CHROME_BROWSER_SPELLCHECK_MESSAGE_FILTER_H_ diff --git a/chrome/browser/spellcheck_message_filter_browsertest.cc b/chrome/browser/spellcheck_message_filter_browsertest.cc new file mode 100644 index 0000000..4599150 --- /dev/null +++ b/chrome/browser/spellcheck_message_filter_browsertest.cc @@ -0,0 +1,72 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/command_line.h" +#include "base/message_loop.h" +#include "base/utf_string_conversions.h" +#include "chrome/browser/spellcheck_message_filter.h" +#include "chrome/common/render_messages.h" +#include "chrome/test/in_process_browser_test.h" +#include "chrome/test/ui_test_utils.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebTextCheckingResult.h" + +namespace { + +typedef InProcessBrowserTest SpellCheckMessageFilterBrowserTest; + +// Fake filter for testing, which stores sent messages and +// allows verification by the test case. +class TestingSpellCheckMessageFilter : public SpellCheckMessageFilter { + public: + explicit TestingSpellCheckMessageFilter(MessageLoopForUI* loop) + : loop_(loop) { } + + ~TestingSpellCheckMessageFilter() { + for (std::vector<IPC::Message*>::iterator i = sent_messages_.begin(); + i != sent_messages_.end(); + ++i) { + delete *i; + } + } + + virtual bool Send(IPC::Message* message) { + sent_messages_.push_back(message); + loop_->PostTask(FROM_HERE, new MessageLoop::QuitTask()); + return true; + } + + std::vector<IPC::Message*> sent_messages_; + MessageLoopForUI* loop_; +}; + +// Uses browsertest to setup chrome threads. +IN_PROC_BROWSER_TEST_F(SpellCheckMessageFilterBrowserTest, + SpellCheckReturnMessage) { + scoped_refptr<TestingSpellCheckMessageFilter> target + (new TestingSpellCheckMessageFilter(MessageLoopForUI::current())); + + ViewHostMsg_SpellChecker_PlatformRequestTextCheck to_be_received + (123, 456, 789, UTF8ToUTF16("zz.")); + bool handled = false; + target->OnMessageReceived(to_be_received, &handled); + EXPECT_TRUE(handled); + + MessageLoopForUI::current()->Run(); + EXPECT_EQ(1U, target->sent_messages_.size()); + + int sent_identifier; + int sent_tag; + std::vector<WebKit::WebTextCheckingResult> sent_results; + bool ok = ViewMsg_SpellChecker_RespondTextCheck::Read( + target->sent_messages_[0], &sent_identifier, &sent_tag, &sent_results); + EXPECT_TRUE(ok); + EXPECT_EQ(1U, sent_results.size()); + EXPECT_EQ(sent_results[0].position(), 0); + EXPECT_EQ(sent_results[0].length(), 2); + EXPECT_EQ(sent_results[0].error(), + WebKit::WebTextCheckingResult::ErrorSpelling); +} + +} // namespace diff --git a/chrome/browser/spellchecker_linux.cc b/chrome/browser/spellchecker_linux.cc index 8637edc..5321e9e 100644 --- a/chrome/browser/spellchecker_linux.cc +++ b/chrome/browser/spellchecker_linux.cc @@ -57,4 +57,10 @@ void IgnoreWord(const string16& word) {} void CloseDocumentWithTag(int tag) {} +void RequestTextCheck(int route_id, + int identifier, + int document_tag, + const string16& text, + BrowserMessageFilter* destination) {} + } // namespace SpellCheckerPlatform diff --git a/chrome/browser/spellchecker_mac.mm b/chrome/browser/spellchecker_mac.mm index 24b6e15..b2af3ec 100644 --- a/chrome/browser/spellchecker_mac.mm +++ b/chrome/browser/spellchecker_mac.mm @@ -11,15 +11,84 @@ #include "base/logging.h" #include "base/metrics/histogram.h" +#include "base/task.h" #include "base/time.h" #include "base/sys_string_conversions.h" +#include "chrome/browser/browser_thread.h" +#include "chrome/browser/browser_message_filter.h" +#include "chrome/common/render_messages.h" #include "chrome/common/spellcheck_common.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebTextCheckingResult.h" using base::TimeTicks; namespace { // The number of characters in the first part of the language code. const unsigned int kShortLanguageCodeSize = 2; +// TextCheckingTask is reserved for spell checking against large size +// of text, which possible contains multiple paragrpahs. Checking +// that size of text might take time, and should be done as a task on +// the FILE thread. +// +// The result of the check is returned back as a +// ViewMsg_SpellChecker_RespondTextCheck message. +class TextCheckingTask : public Task { + public: + TextCheckingTask(BrowserMessageFilter* destination, + int route_id, + int identifier, + const string16& text, + int document_tag) + : destination_(destination), + route_id_(route_id), + identifier_(identifier), + text_(text), + document_tag_(document_tag) { + } + + virtual void Run() { + // TODO(morrita): Use [NSSpellChecker requestCheckingOfString] + // when the build target goes up to 10.6 + std::vector<WebKit::WebTextCheckingResult> check_results; + NSString* text_to_check = base::SysUTF16ToNSString(text_); + size_t starting_at = 0; + while (starting_at < text_.size()) { + NSRange range = [[NSSpellChecker sharedSpellChecker] + checkSpellingOfString:text_to_check + startingAt:starting_at + language:nil + wrap:NO + inSpellDocumentWithTag:document_tag_ + wordCount:NULL]; + if (range.length == 0) + break; + check_results.push_back(WebKit::WebTextCheckingResult( + WebKit::WebTextCheckingResult::ErrorSpelling, + range.location, + range.length)); + starting_at = range.location + range.length; + } + + BrowserThread::PostTask( + BrowserThread::IO, + FROM_HERE, + NewRunnableMethod( + destination_.get(), + &BrowserMessageFilter::Send, + new ViewMsg_SpellChecker_RespondTextCheck(route_id_, + identifier_, + document_tag_, + check_results))); + } + + private: + scoped_refptr<BrowserMessageFilter> destination_; + int route_id_; + int identifier_; + string16 text_; + int document_tag_; +}; + // A private utility function to convert hunspell language codes to OS X // language codes. NSString* ConvertLanguageCodeToMac(const std::string& hunspell_lang_code) { @@ -213,7 +282,17 @@ void IgnoreWord(const string16& word) { void CloseDocumentWithTag(int tag) { [[NSSpellChecker sharedSpellChecker] - closeSpellDocumentWithTag:static_cast<NSInteger>(tag)]; + closeSpellDocumentWithTag:static_cast<NSInteger>(tag)]; +} + +void RequestTextCheck(int route_id, + int identifier, + int document_tag, + const string16& text, BrowserMessageFilter* destination) { + BrowserThread::PostTask( + BrowserThread::FILE, FROM_HERE, + new TextCheckingTask( + destination, route_id, identifier, text, document_tag)); } } // namespace SpellCheckerPlatform diff --git a/chrome/browser/spellchecker_platform_engine.h b/chrome/browser/spellchecker_platform_engine.h index edc8f310..1f192af 100644 --- a/chrome/browser/spellchecker_platform_engine.h +++ b/chrome/browser/spellchecker_platform_engine.h @@ -12,8 +12,11 @@ #include <string> #include <vector> +#include "base/callback.h" #include "base/string16.h" +class BrowserMessageFilter; + namespace SpellCheckerPlatform { // Get the languages supported by the platform spellchecker and store them in @@ -81,6 +84,15 @@ void IgnoreWord(const string16& word); // document can now be forgotten. void CloseDocumentWithTag(int tag); +// Requests an asyncronous spell and grammar checking. +// The result is returned to an IPC message to |destination| thus it should +// not be null. +void RequestTextCheck(int route_id, + int identifier, + int document_tag, + const string16& text, + BrowserMessageFilter* destination); + } // namespace SpellCheckerPlatform #endif // CHROME_BROWSER_SPELLCHECKER_PLATFORM_ENGINE_H_ diff --git a/chrome/browser/spellchecker_win.cc b/chrome/browser/spellchecker_win.cc index 1f318a0..ec0717e 100644 --- a/chrome/browser/spellchecker_win.cc +++ b/chrome/browser/spellchecker_win.cc @@ -57,4 +57,10 @@ void IgnoreWord(const string16& word) {} void CloseDocumentWithTag(int tag) {} +void RequestTextCheck(int route_id, + int identifier, + int document_tag, + const string16& text, + BrowserMessageFilter* destination) {} + } // namespace SpellCheckerPlatform diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index e5dca30..53a9437 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -1975,6 +1975,8 @@ 'browser/speech/speech_recognizer.h', 'browser/spellcheck_host.cc', 'browser/spellcheck_host.h', + 'browser/spellcheck_message_filter.cc', + 'browser/spellcheck_message_filter.h', 'browser/spellchecker_linux.cc', 'browser/spellchecker_mac.mm', 'browser/spellchecker_platform_engine.h', diff --git a/chrome/chrome_renderer.gypi b/chrome/chrome_renderer.gypi index df03626..aa7ab3c 100644 --- a/chrome/chrome_renderer.gypi +++ b/chrome/chrome_renderer.gypi @@ -233,6 +233,8 @@ 'renderer/searchbox_extension.h', 'renderer/speech_input_dispatcher.cc', 'renderer/speech_input_dispatcher.h', + 'renderer/spellchecker/spellcheck_provider.cc', + 'renderer/spellchecker/spellcheck_provider.h', 'renderer/spellchecker/spellcheck.cc', 'renderer/spellchecker/spellcheck.h', 'renderer/spellchecker/spellcheck_worditerator.cc', diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index fd64133..19b3b3e 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -1828,6 +1828,7 @@ 'renderer/safe_browsing/phishing_url_feature_extractor_unittest.cc', 'renderer/safe_browsing/scorer_unittest.cc', 'renderer/spellchecker/spellcheck_unittest.cc', + 'renderer/spellchecker/spellcheck_provider_unittest.cc', 'renderer/spellchecker/spellcheck_worditerator_unittest.cc', 'service/cloud_print/cloud_print_helpers_unittest.cc', 'service/cloud_print/cloud_print_url_fetcher_unittest.cc', @@ -2433,6 +2434,7 @@ ], 'sources': [ 'renderer/external_popup_menu_unittest.cc', + 'browser/spellcheck_message_filter_browsertest.cc', ], }, { # else: OS != "mac" 'sources!': [ diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h index fc449b8..640135b 100644 --- a/chrome/common/render_messages_internal.h +++ b/chrome/common/render_messages_internal.h @@ -278,6 +278,10 @@ IPC_MESSAGE_ROUTED0(ViewMsg_ToggleSpellCheck) IPC_MESSAGE_ROUTED0(ViewMsg_Delete) IPC_MESSAGE_ROUTED0(ViewMsg_SelectAll) IPC_MESSAGE_ROUTED1(ViewMsg_ToggleSpellPanel, bool) +IPC_MESSAGE_ROUTED3(ViewMsg_SpellChecker_RespondTextCheck, + int /* request identifier given by WebKit */, + int /* document tag */, + std::vector<WebKit::WebTextCheckingResult>) // This message tells the renderer to advance to the next misspelling. It is // sent when the user clicks the "Find Next" button on the spelling panel. @@ -2356,6 +2360,12 @@ IPC_SYNC_MESSAGE_CONTROL1_1( string16 /* word */, std::vector<string16> /* suggestions */) +IPC_MESSAGE_CONTROL4(ViewHostMsg_SpellChecker_PlatformRequestTextCheck, + int /* route_id for response */, + int /* request identifier given by WebKit */, + int /* document tag */, + string16 /* sentence */) + //--------------------------------------------------------------------------- // Geolocation services messages diff --git a/chrome/common/webkit_param_traits.cc b/chrome/common/webkit_param_traits.cc index 12c885a..294ef5c 100644 --- a/chrome/common/webkit_param_traits.cc +++ b/chrome/common/webkit_param_traits.cc @@ -175,4 +175,45 @@ void ParamTraits<WebKit::WebCompositionUnderline>::Log(const param_type& p, l->append(")"); } +void ParamTraits<WebKit::WebTextCheckingResult>::Write(Message* m, + const param_type& p) { + WriteParam(m, static_cast<int>(p.error())); + WriteParam(m, p.position()); + WriteParam(m, p.length()); +} + +bool ParamTraits<WebKit::WebTextCheckingResult>::Read(const Message* m, + void** iter, + param_type* p) { + int error = 0; + if (!ReadParam(m, iter, &error)) + return false; + if (error != WebKit::WebTextCheckingResult::ErrorSpelling && + error != WebKit::WebTextCheckingResult::ErrorGrammar) + return false; + int position = 0; + if (!ReadParam(m, iter, &position)) + return false; + int length = 0; + if (!ReadParam(m, iter, &length)) + return false; + + *p = WebKit::WebTextCheckingResult( + static_cast<WebKit::WebTextCheckingResult::Error>(error), + position, + length); + return true; +} + +void ParamTraits<WebKit::WebTextCheckingResult>::Log(const param_type& p, + std::string* l) { + l->append("("); + LogParam(static_cast<int>(p.error()), l); + l->append(", "); + LogParam(p.position(), l); + l->append(", "); + LogParam(p.length(), l); + l->append(")"); +} + } // namespace IPC diff --git a/chrome/common/webkit_param_traits.h b/chrome/common/webkit_param_traits.h index 8d540c9..11a3aac 100644 --- a/chrome/common/webkit_param_traits.h +++ b/chrome/common/webkit_param_traits.h @@ -32,6 +32,7 @@ #include "third_party/WebKit/Source/WebKit/chromium/public/WebFileError.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebPopupType.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebTextCheckingResult.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebTextDirection.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebTextInputType.h" @@ -273,6 +274,14 @@ struct SimilarTypeTraits<WebKit::WebFileError> { typedef int Type; }; +template <> +struct ParamTraits<WebKit::WebTextCheckingResult> { + typedef WebKit::WebTextCheckingResult param_type; + static void Write(Message* m, const param_type& p); + static bool Read(const Message* m, void** iter, param_type* r); + static void Log(const param_type& p, std::string* l); +}; + } // namespace IPC #endif // CHROME_COMMON_WEBKIT_PARAM_TRAITS_H_ diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc index 48a3f62..53697cfef 100644 --- a/chrome/renderer/render_view.cc +++ b/chrome/renderer/render_view.cc @@ -91,6 +91,7 @@ #include "chrome/renderer/safe_browsing/phishing_classifier_delegate.h" #include "chrome/renderer/searchbox.h" #include "chrome/renderer/speech_input_dispatcher.h" +#include "chrome/renderer/spellchecker/spellcheck_provider.h" #include "chrome/renderer/spellchecker/spellcheck.h" #include "chrome/renderer/translate_helper.h" #include "chrome/renderer/user_script_idle_scheduler.h" @@ -150,6 +151,8 @@ #include "third_party/WebKit/Source/WebKit/chromium/public/WebSize.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebStorageNamespace.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebTextCheckingCompletion.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebTextCheckingResult.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebURL.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebURLError.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebURLRequest.h" @@ -264,6 +267,7 @@ using WebKit::WebSize; using WebKit::WebStorageNamespace; using WebKit::WebString; using WebKit::WebTextAffinity; +using WebKit::WebTextCheckingResult; using WebKit::WebTextDirection; using WebKit::WebURL; using WebKit::WebURLError; @@ -582,6 +586,7 @@ RenderView::RenderView(RenderThreadBase* render_thread, device_orientation_dispatcher_(NULL), print_helper_(NULL), searchbox_(NULL), + spellcheck_provider_(NULL), accessibility_ack_pending_(false), pending_app_icon_requests_(0), session_storage_namespace_id_(session_storage_namespace_id) { @@ -657,6 +662,10 @@ RenderView::RenderView(RenderThreadBase* render_thread, print_helper_ = new PrintWebViewHelper(this); searchbox_ = new SearchBox(this); + RenderThread* current_thread = RenderThread::current(); + SpellCheck* spellcheck = current_thread ? current_thread->spellchecker() : 0; + spellcheck_provider_ = new SpellCheckProvider(this, spellcheck); + if (CommandLine::ForCurrentProcess()->HasSwitch( switches::kEnableClientSidePhishingDetection)) { new safe_browsing::PhishingClassifierDelegate(this, NULL); @@ -2301,6 +2310,12 @@ void RenderView::spellCheck(const WebString& text, } } +void RenderView::requestCheckingOfText( + const WebString& text, + WebKit::WebTextCheckingCompletion* completion) { + spellcheck_provider_->RequestTextChecking(text, document_tag_, completion); +} + WebString RenderView::autoCorrectWord(const WebKit::WebString& word) { string16 autocorrect_word; const CommandLine& command_line = *CommandLine::ForCurrentProcess(); diff --git a/chrome/renderer/render_view.h b/chrome/renderer/render_view.h index d16012c..dfefb9e 100644 --- a/chrome/renderer/render_view.h +++ b/chrome/renderer/render_view.h @@ -16,6 +16,7 @@ #include "app/surface/transport_dib.h" #include "base/basictypes.h" #include "base/gtest_prod_util.h" +#include "base/id_map.h" #include "base/linked_ptr.h" #include "base/observer_list.h" #include "base/timer.h" @@ -77,6 +78,7 @@ class RenderViewVisitor; class SearchBox; class SkBitmap; class SpeechInputDispatcher; +class SpellCheckProvider; class WebPluginDelegatePepper; class WebPluginDelegateProxy; struct ContextMenuMediaParams; @@ -145,6 +147,7 @@ class WebPlugin; class WebSpeechInputController; class WebSpeechInputListener; class WebStorageNamespace; +class WebTextCheckingCompletion; class WebURLRequest; class WebView; struct WebContextMenuData; @@ -415,6 +418,9 @@ class RenderView : public RenderWidget, virtual void spellCheck(const WebKit::WebString& text, int& offset, int& length); + virtual void requestCheckingOfText( + const WebKit::WebString& text, + WebKit::WebTextCheckingCompletion* completion); virtual WebKit::WebString autoCorrectWord( const WebKit::WebString& misspelled_word); virtual void showSpellingUI(bool show); @@ -1325,6 +1331,11 @@ class RenderView : public RenderWidget, // Weak pointer since it implements RenderViewObserver interface. SearchBox* searchbox_; + // spellcheck provider which is registered as a view observer. + // Note that RenderViewObserver subclasses like this will be deleted + // automatically during RenderView destruction. + SpellCheckProvider* spellcheck_provider_; + scoped_refptr<AudioMessageFilter> audio_message_filter_; // Handles accessibility requests into the renderer side, as well as diff --git a/chrome/renderer/render_view_observer.cc b/chrome/renderer/render_view_observer.cc index 7e771e3..9c9a4a8 100644 --- a/chrome/renderer/render_view_observer.cc +++ b/chrome/renderer/render_view_observer.cc @@ -7,8 +7,11 @@ #include "chrome/renderer/render_view.h" RenderViewObserver::RenderViewObserver(RenderView* render_view) - : render_view_(render_view), routing_id_(render_view->routing_id()) { - render_view_->AddObserver(this); + : render_view_(render_view), + routing_id_(render_view ? render_view->routing_id() : 0) { + // |render_view| can be NULL on unit testing. + if (render_view_) + render_view_->AddObserver(this); } RenderViewObserver::~RenderViewObserver() { diff --git a/chrome/renderer/spellchecker/spellcheck.h b/chrome/renderer/spellchecker/spellcheck.h index 42dde87..243da89 100644 --- a/chrome/renderer/spellchecker/spellcheck.h +++ b/chrome/renderer/spellchecker/spellcheck.h @@ -22,6 +22,8 @@ namespace file_util { class MemoryMappedFile; } +// TODO(morrita): Needs reorg with SpellCheckProvider. +// See http://crbug.com/73699. class SpellCheck { public: SpellCheck(); @@ -65,6 +67,12 @@ class SpellCheck { // |hunspell_| has been initialized. void WordAdded(const std::string& word); + // Returns true if the spellchecker delegate checking to a system-provided + // checker on the browser process. + bool is_using_platform_spelling_engine() const { + return is_using_platform_spelling_engine_; + } + private: // Initializes the Hunspell dictionary, or does nothing if |hunspell_| is // non-null. This blocks. diff --git a/chrome/renderer/spellchecker/spellcheck_provider.cc b/chrome/renderer/spellchecker/spellcheck_provider.cc new file mode 100644 index 0000000..779844d --- /dev/null +++ b/chrome/renderer/spellchecker/spellcheck_provider.cc @@ -0,0 +1,72 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/renderer/spellchecker/spellcheck_provider.h" + +#include "chrome/common/render_messages.h" +#include "chrome/renderer/render_thread.h" +#include "chrome/renderer/spellchecker/spellcheck.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebTextCheckingCompletion.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebTextCheckingResult.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebVector.h" + +using WebKit::WebString; +using WebKit::WebTextCheckingCompletion; +using WebKit::WebTextCheckingResult; + +SpellCheckProvider::SpellCheckProvider(RenderView* render_view, + SpellCheck* spellcheck) + : RenderViewObserver(render_view), + spellcheck_(spellcheck) { +} + +SpellCheckProvider::~SpellCheckProvider() { +} + +void SpellCheckProvider::RequestTextChecking( + const WebString& text, + int document_tag, + WebTextCheckingCompletion* completion) { + // Text check (unified request for grammar and spell check) is only + // available for browser process, so we ask the system sellchecker + // over IPC or return an empty result if the checker is not + // available. + if (!is_using_platform_spelling_engine()) { + completion->didFinishCheckingText + (std::vector<WebTextCheckingResult>()); + return; + } + + Send(new ViewHostMsg_SpellChecker_PlatformRequestTextCheck( + routing_id(), + text_check_completions_.Add(completion), + document_tag, + text)); +} + +void SpellCheckProvider::OnSpellCheckerRespondTextCheck( + int identifier, + int tag, + const std::vector<WebTextCheckingResult>& results) { + WebKit::WebTextCheckingCompletion* completion = + text_check_completions_.Lookup(identifier); + if (!completion) + return; + text_check_completions_.Remove(identifier); + completion->didFinishCheckingText(results); +} + +bool SpellCheckProvider::OnMessageReceived(const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(SpellCheckProvider, message) + IPC_MESSAGE_HANDLER(ViewMsg_SpellChecker_RespondTextCheck, + OnSpellCheckerRespondTextCheck) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +bool SpellCheckProvider::is_using_platform_spelling_engine() const { + return spellcheck_ && spellcheck_->is_using_platform_spelling_engine(); +} diff --git a/chrome/renderer/spellchecker/spellcheck_provider.h b/chrome/renderer/spellchecker/spellcheck_provider.h new file mode 100644 index 0000000..9496dda --- /dev/null +++ b/chrome/renderer/spellchecker/spellcheck_provider.h @@ -0,0 +1,66 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_RENDERER_SPELLCHECKER_SPELLCHECK_PROVIDER_H_ +#define CHROME_RENDERER_SPELLCHECKER_SPELLCHECK_PROVIDER_H_ +#pragma once + +#include <vector> + +#include "base/id_map.h" +#include "chrome/renderer/render_view_observer.h" + +class RenderView; +class SpellCheck; + +namespace WebKit { +class WebString; +class WebTextCheckingResult; +class WebTextCheckingCompletion; +} + +// This class deals with invoking browser-side spellcheck mechanism +// which is done asynchronously. +class SpellCheckProvider : public RenderViewObserver { + public: + typedef IDMap<WebKit::WebTextCheckingCompletion> WebTextCheckCompletions; + + SpellCheckProvider(RenderView* render_view, SpellCheck* spellcheck); + virtual ~SpellCheckProvider(); + + // Reqeusts async spell and grammar checker to the platform text + // checker, which is available on the browser process. + void RequestTextChecking( + const WebKit::WebString& text, + int document_tag, + WebKit::WebTextCheckingCompletion* completion); + + // Check the availability of the platform spellchecker. + // Makes this virtual for overriding on the unittest. + virtual bool is_using_platform_spelling_engine() const; + + // The number of ongoing IPC requests. + size_t pending_text_request_size() const { + return text_check_completions_.size(); + } + + // RenderViewObserver implementation. + virtual bool OnMessageReceived(const IPC::Message& message); + + private: + // A message handler that receives async results for RequestTextChecking(). + void OnSpellCheckerRespondTextCheck( + int identifier, + int tag, + const std::vector<WebKit::WebTextCheckingResult>& results); + + // Holds ongoing spellchecking operations, assigns IDs for the IPC routing. + WebTextCheckCompletions text_check_completions_; + // Spellcheck implementation for use. Weak reference. + SpellCheck* spellcheck_; + + DISALLOW_COPY_AND_ASSIGN(SpellCheckProvider); +}; + +#endif // CHROME_RENDERER_SPELLCHECKER_SPELLCHECK_PROVIDER_H_ diff --git a/chrome/renderer/spellchecker/spellcheck_provider_unittest.cc b/chrome/renderer/spellchecker/spellcheck_provider_unittest.cc new file mode 100644 index 0000000..bb63f19 --- /dev/null +++ b/chrome/renderer/spellchecker/spellcheck_provider_unittest.cc @@ -0,0 +1,178 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <vector> + +#include "base/utf_string_conversions.h" +#include "chrome/common/render_messages.h" +#include "chrome/renderer/spellchecker/spellcheck_provider.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" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebVector.h" + +namespace { + +// Faked test target, which stores sent message for verification, +// and allows manipulate |is_using_platform_spelling_engine| parameter. +class TestingSpellCheckProvider : public SpellCheckProvider { + public: + TestingSpellCheckProvider() + : SpellCheckProvider(NULL, NULL), + is_using_platform_spelling_engine_(true) { + } + + virtual ~TestingSpellCheckProvider() { + for (std::vector<IPC::Message*>::iterator i = messages_.begin(); + i != messages_.end(); + ++i) { + delete *i; + } + } + + virtual bool Send(IPC::Message* message) { + messages_.push_back(message); + return true; + } + + virtual bool is_using_platform_spelling_engine() const { + return is_using_platform_spelling_engine_; + } + + std::vector<IPC::Message*> messages_; + bool is_using_platform_spelling_engine_; +}; + +// A fake completion object for verification. +class FakeTextCheckingCompletion : public WebKit::WebTextCheckingCompletion { + public: + FakeTextCheckingCompletion() + : 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_; +}; + +class SpellCheckProviderTest : public testing::Test { + public: + SpellCheckProviderTest() { } + virtual ~SpellCheckProviderTest() { } + + protected: + TestingSpellCheckProvider provider_; +}; + +struct MessageParameters { + MessageParameters() + : router_id(0), + request_id(0), + document_tag(0) { } + + int router_id; + int request_id; + int document_tag; + string16 text; +}; + +MessageParameters ReadPlatformRequestTextCheck(IPC::Message* message) { + MessageParameters parameters; + bool ok = ViewHostMsg_SpellChecker_PlatformRequestTextCheck::Read( + message, + ¶meters.router_id, + ¶meters.request_id, + ¶meters.document_tag, + ¶meters.text); + EXPECT_TRUE(ok); + return parameters; +} + +void FakeMessageArrival(SpellCheckProvider* provider, + const MessageParameters& parameters) { + std::vector<WebKit::WebTextCheckingResult> fake_result; + bool handled = provider->OnMessageReceived( + ViewMsg_SpellChecker_RespondTextCheck + (0, + parameters.request_id, + parameters.document_tag, + fake_result)); + EXPECT_TRUE(handled); +} + +TEST_F(SpellCheckProviderTest, SingleRoundtripSuccess) { + FakeTextCheckingCompletion completion; + int document_tag = 123; + + provider_.RequestTextChecking(WebKit::WebString("hello"), + document_tag, + &completion); + EXPECT_EQ(completion.completion_count_, 0U); + EXPECT_EQ(provider_.messages_.size(), 1U); + EXPECT_EQ(provider_.pending_text_request_size(), 1U); + + MessageParameters read_parameters = + ReadPlatformRequestTextCheck(provider_.messages_[0]); + EXPECT_EQ(read_parameters.text, UTF8ToUTF16("hello")); + + FakeMessageArrival(&provider_, read_parameters); + EXPECT_EQ(completion.completion_count_, 1U); + EXPECT_EQ(provider_.pending_text_request_size(), 0U); +} + +TEST_F(SpellCheckProviderTest, TwoRoundtripSuccess) { + int document_tag = 123; + + FakeTextCheckingCompletion completion1; + provider_.RequestTextChecking(WebKit::WebString("hello"), + document_tag, + &completion1); + FakeTextCheckingCompletion completion2; + provider_.RequestTextChecking(WebKit::WebString("bye"), + document_tag, + &completion2); + + EXPECT_EQ(completion1.completion_count_, 0U); + EXPECT_EQ(completion2.completion_count_, 0U); + EXPECT_EQ(provider_.messages_.size(), 2U); + EXPECT_EQ(provider_.pending_text_request_size(), 2U); + + MessageParameters read_parameters1 = + ReadPlatformRequestTextCheck(provider_.messages_[0]); + EXPECT_EQ(read_parameters1.text, UTF8ToUTF16("hello")); + + MessageParameters read_parameters2 = + ReadPlatformRequestTextCheck(provider_.messages_[1]); + EXPECT_EQ(read_parameters2.text, UTF8ToUTF16("bye")); + + FakeMessageArrival(&provider_, read_parameters1); + EXPECT_EQ(completion1.completion_count_, 1U); + EXPECT_EQ(completion2.completion_count_, 0U); + EXPECT_EQ(provider_.pending_text_request_size(), 1U); + + FakeMessageArrival(&provider_, read_parameters2); + EXPECT_EQ(completion1.completion_count_, 1U); + EXPECT_EQ(completion2.completion_count_, 1U); + EXPECT_EQ(provider_.pending_text_request_size(), 0U); +} + +TEST_F(SpellCheckProviderTest, PlatformEngineUnavailable) { + provider_.is_using_platform_spelling_engine_ = false; + + int document_tag = 123; + FakeTextCheckingCompletion completion; + provider_.RequestTextChecking(WebKit::WebString("hello"), + document_tag, + &completion); + EXPECT_EQ(completion.completion_count_, 1U); + EXPECT_EQ(provider_.messages_.size(), 0U); + EXPECT_EQ(provider_.pending_text_request_size(), 0U); +} + +} // namespace diff --git a/webkit/glue/webpreferences.cc b/webkit/glue/webpreferences.cc index 86c40f6..25fa0bf 100644 --- a/webkit/glue/webpreferences.cc +++ b/webkit/glue/webpreferences.cc @@ -65,6 +65,7 @@ WebPreferences::WebPreferences() experimental_webgl_enabled(false), gl_multisampling_enabled(true), show_composited_layer_borders(false), + asynchronous_spell_checking_enabled(true), accelerated_compositing_enabled(false), accelerated_layers_enabled(false), accelerated_video_enabled(false), @@ -187,6 +188,9 @@ void WebPreferences::Apply(WebView* web_view) const { // Enable memory info reporting to page if requested on the command line. settings->setMemoryInfoEnabled(memory_info_enabled); + settings->setAsynchronousSpellCheckingEnabled( + asynchronous_spell_checking_enabled); + for (WebInspectorPreferences::const_iterator it = inspector_settings.begin(); it != inspector_settings.end(); ++it) web_view->setInspectorSetting(WebString::fromUTF8(it->first), diff --git a/webkit/glue/webpreferences.h b/webkit/glue/webpreferences.h index 468e9b4..c163dc9 100644 --- a/webkit/glue/webpreferences.h +++ b/webkit/glue/webpreferences.h @@ -70,6 +70,7 @@ struct WebPreferences { bool experimental_webgl_enabled; bool gl_multisampling_enabled; bool show_composited_layer_borders; + bool asynchronous_spell_checking_enabled; bool accelerated_compositing_enabled; bool accelerated_layers_enabled; bool accelerated_video_enabled; |