diff options
6 files changed, 186 insertions, 21 deletions
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index 9da446b..212950f 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc @@ -711,7 +711,7 @@ void ChromeContentBrowserClient::RenderProcessHostCreated( new SearchProviderInstallStateMessageFilter(id, profile)); host->GetChannel()->AddFilter(new SpellCheckMessageFilter(id)); #if defined(OS_MACOSX) - host->GetChannel()->AddFilter(new SpellCheckMessageFilterMac()); + host->GetChannel()->AddFilter(new SpellCheckMessageFilterMac(id)); #endif host->GetChannel()->AddFilter(new ChromeNetBenchmarkingMessageFilter( id, profile, context)); diff --git a/chrome/browser/spellchecker/spellcheck_message_filter_mac.cc b/chrome/browser/spellchecker/spellcheck_message_filter_mac.cc index 88c7cbb..1ff42c2 100644 --- a/chrome/browser/spellchecker/spellcheck_message_filter_mac.cc +++ b/chrome/browser/spellchecker/spellcheck_message_filter_mac.cc @@ -4,12 +4,168 @@ #include "chrome/browser/spellchecker/spellcheck_message_filter_mac.h" +#include "base/bind.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/spellchecker/spellcheck_platform_mac.h" +#include "chrome/browser/spellchecker/spelling_service_client.h" #include "chrome/common/spellcheck_messages.h" +#include "chrome/common/spellcheck_result.h" +#include "content/public/browser/render_process_host.h" using content::BrowserThread; -SpellCheckMessageFilterMac::SpellCheckMessageFilterMac() {} +class SpellingRequest { + public: + SpellingRequest(SpellingServiceClient* client, + content::BrowserMessageFilter* destination, + int render_process_id); + + void RequestCheck(const string16& text, + int route_id, + int identifier, + int document_tag); + private: + // Request server-side checking. + void RequestRemoteCheck(const string16& text); + + // Request a check from local spell checker. + void RequestLocalCheck(const string16& text, int document_tag); + + // Check if all pending requests are done, send reply to render process if so. + void OnCheckCompleted(); + + // Called when server-side checking is complete. + void OnRemoteCheckCompleted(bool success, + const string16& text, + const std::vector<SpellCheckResult>& results); + + // Called when local checking is complete. + void OnLocalCheckCompleted(const std::vector<SpellCheckResult>& results); + + std::vector<SpellCheckResult> local_results_; + std::vector<SpellCheckResult> remote_results_; + + bool local_pending_; + bool remote_pending_; + bool remote_success_; + + SpellingServiceClient* client_; // Owned by |destination|. + content::BrowserMessageFilter* destination_; // ref-counted. + int render_process_id_; + + int route_id_; + int identifier_; + int document_tag_; +}; + +SpellingRequest::SpellingRequest(SpellingServiceClient* client, + content::BrowserMessageFilter* destination, + int render_process_id) + : local_pending_(true), + remote_pending_(true), + client_(client), + destination_(destination), + render_process_id_(render_process_id), + route_id_(-1), + identifier_(-1), + document_tag_(-1) { + destination_->AddRef(); +} + +void SpellingRequest::RequestCheck(const string16& text, + int route_id, + int identifier, + int document_tag) { + DCHECK(!text.empty()); + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + + route_id_ = route_id; + identifier_ = identifier; + document_tag_ = document_tag; + + // Send the remote query out. + RequestRemoteCheck(text); + RequestLocalCheck(text, document_tag_); +} + +void SpellingRequest::RequestRemoteCheck(const string16& text) { + Profile* profile = NULL; + content::RenderProcessHost* host = + content::RenderProcessHost::FromID(render_process_id_); + if (host) + profile = Profile::FromBrowserContext(host->GetBrowserContext()); + + client_->RequestTextCheck( + profile, + SpellingServiceClient::SPELLCHECK, + text, + base::Bind(&SpellingRequest::OnRemoteCheckCompleted, + base::Unretained(this))); +} + +void SpellingRequest::RequestLocalCheck(const string16& text, + int document_tag) { + spellcheck_mac::RequestTextCheck( + document_tag, + text, + base::Bind(&SpellingRequest::OnLocalCheckCompleted, + base::Unretained(this))); +} + +void SpellingRequest::OnCheckCompleted() { + // Final completion can happen on any thread - don't DCHECK thread. + + if (local_pending_ || remote_pending_) + return; + + const std::vector<SpellCheckResult>* check_results = &remote_results_; + if (!remote_success_) + check_results = &local_results_; + + destination_->Send( + new SpellCheckMsg_RespondTextCheck( + route_id_, + identifier_, + *check_results)); + destination_->Release(); + + // Object is self-managed - at this point, its life span is over. + delete this; +} + +void SpellingRequest::OnRemoteCheckCompleted( + bool success, + const string16& text, + const std::vector<SpellCheckResult>& results) { + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + remote_success_ = success; + remote_results_ = results; + remote_pending_ = false; + + OnCheckCompleted(); +} + +void SpellingRequest::OnLocalCheckCompleted( + const std::vector<SpellCheckResult>& results) { + // Local checking can happen on any thread - don't DCHECK thread. + + local_results_ = results; + local_pending_ = false; + + OnCheckCompleted(); +} + + +SpellCheckMessageFilterMac::SpellCheckMessageFilterMac(int render_process_id) + : render_process_id_(render_process_id), + client_(new SpellingServiceClient) { +} + +void SpellCheckMessageFilterMac::OverrideThreadForMessage( + const IPC::Message& message, BrowserThread::ID* thread) { + if (message.type() == SpellCheckHostMsg_RequestTextCheck::ID) + *thread = BrowserThread::UI; +} bool SpellCheckMessageFilterMac::OnMessageReceived(const IPC::Message& message, bool* message_was_ok) { @@ -57,8 +213,10 @@ void SpellCheckMessageFilterMac::OnRequestTextCheck( int route_id, int identifier, const string16& text) { - spellcheck_mac::RequestTextCheck( - route_id, identifier, ToDocumentTag(route_id), text, this); + // SpellingRequest self-destructs. + SpellingRequest* request = + new SpellingRequest(client_.get(), this, render_process_id_); + request->RequestCheck(text, route_id, identifier, ToDocumentTag(route_id)); } int SpellCheckMessageFilterMac::ToDocumentTag(int route_id) { diff --git a/chrome/browser/spellchecker/spellcheck_message_filter_mac.h b/chrome/browser/spellchecker/spellcheck_message_filter_mac.h index d5071db..3a7fa2e 100644 --- a/chrome/browser/spellchecker/spellcheck_message_filter_mac.h +++ b/chrome/browser/spellchecker/spellcheck_message_filter_mac.h @@ -7,15 +7,19 @@ #include <map> +#include "chrome/browser/spellchecker/spelling_service_client.h" #include "content/public/browser/browser_message_filter.h" // A message filter implementation that receives // the Mac-specific spell checker requests from SpellCheckProvider. class SpellCheckMessageFilterMac : public content::BrowserMessageFilter { public: - explicit SpellCheckMessageFilterMac(); + explicit SpellCheckMessageFilterMac(int render_process_id); // BrowserMessageFilter implementation. + virtual void OverrideThreadForMessage( + const IPC::Message& message, + content::BrowserThread::ID* thread) OVERRIDE; virtual bool OnMessageReceived(const IPC::Message& message, bool* message_was_ok) OVERRIDE; @@ -37,6 +41,11 @@ class SpellCheckMessageFilterMac : public content::BrowserMessageFilter { void RetireDocumentTag(int route_id); std::map<int,int> tag_map_; + int render_process_id_; + + // A JSON-RPC client that calls the Spelling service in the background. + scoped_ptr<SpellingServiceClient> client_; + DISALLOW_COPY_AND_ASSIGN(SpellCheckMessageFilterMac); }; diff --git a/chrome/browser/spellchecker/spellcheck_message_filter_mac_browsertest.cc b/chrome/browser/spellchecker/spellcheck_message_filter_mac_browsertest.cc index 84ddf07..0a25eeb 100644 --- a/chrome/browser/spellchecker/spellcheck_message_filter_mac_browsertest.cc +++ b/chrome/browser/spellchecker/spellcheck_message_filter_mac_browsertest.cc @@ -19,7 +19,7 @@ class TestingSpellCheckMessageFilter : public SpellCheckMessageFilterMac { public: explicit TestingSpellCheckMessageFilter(MessageLoopForUI* loop) - : SpellCheckMessageFilterMac(), + : SpellCheckMessageFilterMac(0), loop_(loop) { } virtual bool Send(IPC::Message* message) OVERRIDE { diff --git a/chrome/browser/spellchecker/spellcheck_platform_mac.h b/chrome/browser/spellchecker/spellcheck_platform_mac.h index 5796994..098c2b1 100644 --- a/chrome/browser/spellchecker/spellcheck_platform_mac.h +++ b/chrome/browser/spellchecker/spellcheck_platform_mac.h @@ -14,12 +14,18 @@ #include "base/callback_forward.h" #include "base/string16.h" +struct SpellCheckResult; + namespace content { class BrowserMessageFilter; } // namespace content namespace spellcheck_mac { +typedef base::Callback<void( + const std::vector<SpellCheckResult>& /* results */)> + TextCheckCompleteCallback; + // Get the languages supported by the platform spellchecker and store them in // |spellcheck_languages|. Note that they must be converted to // Chromium style codes (en-US not en_US). See spellchecker.cc for a full list. @@ -84,11 +90,9 @@ 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, +void RequestTextCheck(int document_tag, const string16& text, - content::BrowserMessageFilter* destination); + TextCheckCompleteCallback callback); } // namespace spellcheck_mac diff --git a/chrome/browser/spellchecker/spellcheck_platform_mac.mm b/chrome/browser/spellchecker/spellcheck_platform_mac.mm index 81fd517..ad1a06d 100644 --- a/chrome/browser/spellchecker/spellcheck_platform_mac.mm +++ b/chrome/browser/spellchecker/spellcheck_platform_mac.mm @@ -235,13 +235,11 @@ void CloseDocumentWithTag(int tag) { [SharedSpellChecker() closeSpellDocumentWithTag:static_cast<NSInteger>(tag)]; } -void RequestTextCheck(int route_id, - int identifier, - int document_tag, - const string16& text, BrowserMessageFilter* destination) { +void RequestTextCheck(int document_tag, + const string16& text, + TextCheckCompleteCallback callback) { NSString* text_to_check = base::SysUTF16ToNSString(text); NSRange range_to_check = NSMakeRange(0, [text_to_check length]); - destination->AddRef(); [SharedSpellChecker() requestCheckingOfString:text_to_check @@ -262,12 +260,8 @@ void RequestTextCheck(int route_id, [result range].location, [result range].length)); } - destination->Send( - new SpellCheckMsg_RespondTextCheck( - route_id, - identifier, - check_results)); - destination->Release(); + // TODO(groby): Verify we don't need to post from here. + callback.Run(check_results); }]; } |