diff options
author | pinkerton@chromium.org <pinkerton@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-09-09 21:16:05 +0000 |
---|---|---|
committer | pinkerton@chromium.org <pinkerton@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-09-09 21:16:05 +0000 |
commit | 98324891649cf5fa7430c2e231ad5493fdb76c8e (patch) | |
tree | 4c48f7d44d002691e717526bdb2d7870296b10df /chrome/browser | |
parent | 1edc999cee504ed756ee798dfb1bfd95f53b4262 (diff) | |
download | chromium_src-98324891649cf5fa7430c2e231ad5493fdb76c8e.zip chromium_src-98324891649cf5fa7430c2e231ad5493fdb76c8e.tar.gz chromium_src-98324891649cf5fa7430c2e231ad5493fdb76c8e.tar.bz2 |
Adds support for the os x spelling panel to chromium. Users can
now access it from the main menu and context menu and use it to perform
spelling tasks. For more detail, see
http://code.google.com/p/chromium/wiki/SpellingPanelPlanningDoc
Patch from pwicks86@gmail.com (Paul Wicks).
BUG=None
TEST=The spelling panel should work in os x.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@25786 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r-- | chrome/browser/cocoa/rwhvm_editcommand_helper.mm | 1 | ||||
-rw-r--r-- | chrome/browser/renderer_host/render_view_host.cc | 4 | ||||
-rw-r--r-- | chrome/browser/renderer_host/render_view_host.h | 1 | ||||
-rw-r--r-- | chrome/browser/renderer_host/render_widget_host.cc | 12 | ||||
-rw-r--r-- | chrome/browser/renderer_host/render_widget_host.h | 9 | ||||
-rw-r--r-- | chrome/browser/renderer_host/render_widget_host_view_mac.h | 2 | ||||
-rw-r--r-- | chrome/browser/renderer_host/render_widget_host_view_mac.mm | 53 | ||||
-rw-r--r-- | chrome/browser/renderer_host/resource_message_filter.cc | 36 | ||||
-rw-r--r-- | chrome/browser/renderer_host/resource_message_filter.h | 8 | ||||
-rw-r--r-- | chrome/browser/spellcheck_unittest.cc | 99 | ||||
-rw-r--r-- | chrome/browser/spellchecker.cc | 17 | ||||
-rw-r--r-- | chrome/browser/spellchecker.h | 9 | ||||
-rw-r--r-- | chrome/browser/spellchecker_linux.cc | 29 | ||||
-rw-r--r-- | chrome/browser/spellchecker_mac.mm | 57 | ||||
-rw-r--r-- | chrome/browser/spellchecker_platform_engine.h | 26 | ||||
-rw-r--r-- | chrome/browser/spellchecker_win.cc | 29 | ||||
-rw-r--r-- | chrome/browser/tab_contents/render_view_context_menu.cc | 14 |
17 files changed, 345 insertions, 61 deletions
diff --git a/chrome/browser/cocoa/rwhvm_editcommand_helper.mm b/chrome/browser/cocoa/rwhvm_editcommand_helper.mm index 87956b0..c4b1efd 100644 --- a/chrome/browser/cocoa/rwhvm_editcommand_helper.mm +++ b/chrome/browser/cocoa/rwhvm_editcommand_helper.mm @@ -95,6 +95,7 @@ const char* kEditCommands[] = { "selectToMark", "selectWord", "setMark", + "showGuessPanel", "subscript", "superscript", "swapWithMark", diff --git a/chrome/browser/renderer_host/render_view_host.cc b/chrome/browser/renderer_host/render_view_host.cc index 9085996..64fc364 100644 --- a/chrome/browser/renderer_host/render_view_host.cc +++ b/chrome/browser/renderer_host/render_view_host.cc @@ -558,6 +558,10 @@ void RenderViewHost::SelectAll() { Send(new ViewMsg_SelectAll(routing_id())); } +void RenderViewHost::ToggleSpellPanel(bool is_currently_visible) { + Send(new ViewMsg_ToggleSpellPanel(routing_id(), is_currently_visible)); +} + int RenderViewHost::DownloadFavIcon(const GURL& url, int image_size) { if (!url.is_valid()) { NOTREACHED(); diff --git a/chrome/browser/renderer_host/render_view_host.h b/chrome/browser/renderer_host/render_view_host.h index 81637aa..28cadfe 100644 --- a/chrome/browser/renderer_host/render_view_host.h +++ b/chrome/browser/renderer_host/render_view_host.h @@ -275,6 +275,7 @@ class RenderViewHost : public RenderWidgetHost, void AddToDictionary(const std::wstring& word); void Delete(); void SelectAll(); + void ToggleSpellPanel(bool is_currently_visible); // Downloads an image notifying the FavIcon delegate appropriately. The // returned integer uniquely identifies the download for the lifetime of the diff --git a/chrome/browser/renderer_host/render_widget_host.cc b/chrome/browser/renderer_host/render_widget_host.cc index e28b006..473f129 100644 --- a/chrome/browser/renderer_host/render_widget_host.cc +++ b/chrome/browser/renderer_host/render_widget_host.cc @@ -877,3 +877,15 @@ void RenderWidgetHost::ScrollBackingStoreRect(TransportDIB* bitmap, backing_store->ScrollRect(process_->process().handle(), bitmap, bitmap_rect, dx, dy, clip_rect, view_size); } + +void RenderWidgetHost::ToggleSpellPanel(bool is_currently_visible) { + Send(new ViewMsg_ToggleSpellPanel(routing_id(), is_currently_visible)); +} + +void RenderWidgetHost::ReplaceWord(const std::wstring& word) { + Send(new ViewMsg_Replace(routing_id_, word)); +} + +void RenderWidgetHost::AdvanceToNextMisspelling() { + Send(new ViewMsg_AdvanceToNextMisspelling(routing_id_)); +} diff --git a/chrome/browser/renderer_host/render_widget_host.h b/chrome/browser/renderer_host/render_widget_host.h index b06bce3..90e0b9c 100644 --- a/chrome/browser/renderer_host/render_widget_host.h +++ b/chrome/browser/renderer_host/render_widget_host.h @@ -328,6 +328,15 @@ class RenderWidgetHost : public IPC::Channel::Listener, // And to also expose it to the RenderWidgetHostView. virtual gfx::Rect GetRootWindowResizerRect() const; + // Makes an IPC call to toggle the spelling panel. + void ToggleSpellPanel(bool is_currently_visible); + + // Makes an IPC call to tell webkit to replace the currently selected word. + void ReplaceWord(const std::wstring& word); + + // Makes an IPC call to tell webkit to advance to the next misspelling. + void AdvanceToNextMisspelling(); + // Sets the active state (i.e., control tints). virtual void SetActive(bool active); diff --git a/chrome/browser/renderer_host/render_widget_host_view_mac.h b/chrome/browser/renderer_host/render_widget_host_view_mac.h index 1633a52..b8f4146 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_mac.h +++ b/chrome/browser/renderer_host/render_widget_host_view_mac.h @@ -30,7 +30,7 @@ class RWHVMEditCommandHelper; // when it's removed from the view system. @interface RenderWidgetHostViewCocoa - : BaseView <RenderWidgetHostViewMacOwner, NSTextInput> { + : BaseView <RenderWidgetHostViewMacOwner, NSTextInput, NSChangeSpelling> { @private RenderWidgetHostViewMac* renderWidgetHostView_; BOOL canBeKeyView_; diff --git a/chrome/browser/renderer_host/render_widget_host_view_mac.mm b/chrome/browser/renderer_host/render_widget_host_view_mac.mm index fef480b..3587616 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_mac.mm +++ b/chrome/browser/renderer_host/render_widget_host_view_mac.mm @@ -12,6 +12,7 @@ #include "chrome/browser/renderer_host/backing_store.h" #include "chrome/browser/renderer_host/render_process_host.h" #include "chrome/browser/renderer_host/render_widget_host.h" +#include "chrome/browser/spellchecker_platform_engine.h" #include "chrome/common/native_web_keyboard_event.h" #include "skia/ext/platform_canvas.h" #include "webkit/api/public/mac/WebInputEventFactory.h" @@ -690,6 +691,58 @@ void RenderWidgetHostViewMac::SetActive(bool active) { return ([event type] == NSKeyDown) ? YES : NO; } +// Spellchecking methods +// The next three methods are implemented here since this class is the first +// responder for anything in the browser. + +// This message is sent whenever the user specifies that a word should be +// changed from the spellChecker. +- (void)changeSpelling:(id)sender { + // Grab the currently selected word from the spell panel, as this is the word + // that we want to replace the selected word in the text with. + NSString* newWord = [[sender selectedCell] stringValue]; + if (newWord != nil) { + RenderWidgetHostViewMac* thisHostView = [self renderWidgetHostViewMac]; + thisHostView->GetRenderWidgetHost()->ReplaceWord( + base::SysNSStringToWide(newWord)); + } +} + +// This message is sent by NSSpellChecker whenever the next word should be +// advanced to, either after a correction or clicking the "Find Next" button. +// This isn't documented anywhere useful, like in NSSpellProtocol.h with the +// other spelling panel methods. This is probably because Apple assumes that the +// the spelling panel will be used with an NSText, which will automatically +// catch this and advance to the next word for you. Thanks Apple. +- (void)checkSpelling:(id)sender { + RenderWidgetHostViewMac* thisHostView = [self renderWidgetHostViewMac]; + thisHostView->GetRenderWidgetHost()->AdvanceToNextMisspelling(); +} + +// This message is sent by the spelling panel whenever a word is ignored. +- (void)ignoreSpelling:(id)sender { + // Ideally, we would ask the current RenderView for its tag, but that would + // mean making a blocking IPC call from the browser. Instead, + // SpellCheckerPlatform::CheckSpelling remembers the last tag and + // SpellCheckerPlatform::IgnoreWord assumes that is the correct tag. + NSString* wordToIgnore = [sender stringValue]; + if (wordToIgnore != nil) { + SpellCheckerPlatform::IgnoreWord(base::SysNSStringToUTF8(wordToIgnore)); + + // Strangely, the spellingPanel doesn't send checkSpelling after a word is + // ignored, so we have to explicitly call AdvanceToNextMisspelling here. + RenderWidgetHostViewMac* thisHostView = [self renderWidgetHostViewMac]; + thisHostView->GetRenderWidgetHost()->AdvanceToNextMisspelling(); + } +} + +- (void)showGuessPanel:(id)sender { + RenderWidgetHostViewMac* thisHostView = [self renderWidgetHostViewMac]; + thisHostView->GetRenderWidgetHost()->ToggleSpellPanel( + SpellCheckerPlatform::SpellingPanelVisible()); +} + +// END Spellchecking methods // Below is the nasty tooltip stuff -- copied from WebKit's WebHTMLView.mm // with minor modifications for code style and commenting. diff --git a/chrome/browser/renderer_host/resource_message_filter.cc b/chrome/browser/renderer_host/resource_message_filter.cc index 5a21f34..1190fd3 100644 --- a/chrome/browser/renderer_host/resource_message_filter.cc +++ b/chrome/browser/renderer_host/resource_message_filter.cc @@ -27,6 +27,7 @@ #include "chrome/browser/renderer_host/file_system_accessor.h" #include "chrome/browser/renderer_host/render_widget_helper.h" #include "chrome/browser/spellchecker.h" +#include "chrome/browser/spellchecker_platform_engine.h" #include "chrome/browser/worker_host/message_port_dispatcher.h" #include "chrome/browser/worker_host/worker_service.h" #include "chrome/common/appcache/appcache_dispatcher_host.h" @@ -296,8 +297,15 @@ bool ResourceMessageFilter::OnMessageReceived(const IPC::Message& msg) { IPC_MESSAGE_HANDLER(ViewHostMsg_ForwardToWorker, OnForwardToWorker) IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_SpellCheck, OnSpellCheck) + IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetDocumentTag, + OnGetDocumentTag) + IPC_MESSAGE_HANDLER(ViewHostMsg_DocumentWithTagClosed, + OnDocumentWithTagClosed) IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetAutoCorrectWord, OnGetAutoCorrectWord) + IPC_MESSAGE_HANDLER(ViewHostMsg_ShowSpellingPanel, OnShowSpellingPanel) + IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateSpellingPanelWithMisspelledWord, + OnUpdateSpellingPanelWithMisspelledWord) IPC_MESSAGE_HANDLER(ViewHostMsg_DnsPrefetch, OnDnsPrefetch) IPC_MESSAGE_HANDLER(ViewHostMsg_RendererHistograms, OnRendererHistograms) @@ -376,7 +384,7 @@ void ResourceMessageFilter::OnReceiveContextMenuMsg(const IPC::Message& msg) { int misspell_location, misspell_length; bool is_misspelled = !spellchecker_->SpellCheckWord( params.misspelled_word.c_str(), - static_cast<int>(params.misspelled_word.length()), + static_cast<int>(params.misspelled_word.length()), 0, &misspell_location, &misspell_length, ¶ms.dictionary_suggestions); @@ -870,14 +878,14 @@ Clipboard* ResourceMessageFilter::GetClipboard() { // spellings are correct. // // Note: This is called in the IO thread. -void ResourceMessageFilter::OnSpellCheck(const std::wstring& word, +void ResourceMessageFilter::OnSpellCheck(const std::wstring& word, int tag, IPC::Message* reply_msg) { int misspell_location = 0; int misspell_length = 0; if (spellchecker_ != NULL) { spellchecker_->SpellCheckWord(word.c_str(), - static_cast<int>(word.length()), + static_cast<int>(word.length()), tag, &misspell_location, &misspell_length, NULL); } @@ -887,12 +895,23 @@ void ResourceMessageFilter::OnSpellCheck(const std::wstring& word, return; } +void ResourceMessageFilter::OnGetDocumentTag(IPC::Message* reply_msg) { + int tag = SpellCheckerPlatform::GetDocumentTag(); + ViewHostMsg_GetDocumentTag::WriteReplyParams(reply_msg, tag); + Send(reply_msg); + return; +} + +void ResourceMessageFilter::OnDocumentWithTagClosed(int tag) { + SpellCheckerPlatform::CloseDocumentWithTag(tag); +} void ResourceMessageFilter::OnGetAutoCorrectWord(const std::wstring& word, + int tag, IPC::Message* reply_msg) { std::wstring autocorrect_word; if (spellchecker_ != NULL) { - spellchecker_->GetAutoCorrectionWord(word, &autocorrect_word); + spellchecker_->GetAutoCorrectionWord(word, tag, &autocorrect_word); } ViewHostMsg_GetAutoCorrectWord::WriteReplyParams(reply_msg, @@ -901,6 +920,15 @@ void ResourceMessageFilter::OnGetAutoCorrectWord(const std::wstring& word, return; } +void ResourceMessageFilter::OnShowSpellingPanel(bool show) { + SpellCheckerPlatform::ShowSpellingPanel(show); +} + +void ResourceMessageFilter::OnUpdateSpellingPanelWithMisspelledWord( + const std::wstring& word) { + SpellCheckerPlatform::UpdateSpellingPanelWithMisspelledWord(word); +} + void ResourceMessageFilter::Observe(NotificationType type, const NotificationSource &source, const NotificationDetails &details) { diff --git a/chrome/browser/renderer_host/resource_message_filter.h b/chrome/browser/renderer_host/resource_message_filter.h index 4c467c6..743b7f6 100644 --- a/chrome/browser/renderer_host/resource_message_filter.h +++ b/chrome/browser/renderer_host/resource_message_filter.h @@ -159,10 +159,14 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter, void OnDownloadUrl(const IPC::Message& message, const GURL& url, const GURL& referrer); - void OnSpellCheck(const std::wstring& word, + void OnSpellCheck(const std::wstring& word, int tag, IPC::Message* reply_msg); - void OnGetAutoCorrectWord(const std::wstring& word, + void OnGetDocumentTag(IPC::Message* reply_msg); + void OnDocumentWithTagClosed(int tag); + void OnGetAutoCorrectWord(const std::wstring& word, int tag, IPC::Message* reply_msg); + void OnShowSpellingPanel(bool show); + void OnUpdateSpellingPanelWithMisspelledWord(const std::wstring& word); void OnDnsPrefetch(const std::vector<std::string>& hostnames); void OnRendererHistograms(int sequence_number, const std::vector<std::string>& histogram_info); diff --git a/chrome/browser/spellcheck_unittest.cc b/chrome/browser/spellcheck_unittest.cc index 8d97e9e..8c048b2 100644 --- a/chrome/browser/spellcheck_unittest.cc +++ b/chrome/browser/spellcheck_unittest.cc @@ -7,7 +7,9 @@ #include "base/file_util.h" #include "base/message_loop.h" #include "base/path_service.h" +#include "base/sys_string_conversions.h" #include "chrome/browser/spellchecker.h" +#include "chrome/browser/spellchecker_platform_engine.h" #include "chrome/common/chrome_paths.h" #include "testing/gtest/include/gtest/gtest.h" @@ -280,6 +282,7 @@ TEST_F(SpellCheckTest, SpellCheckStrings_EN_US) { int misspelling_length; bool result = spell_checker->SpellCheckWord(kTestCases[i].input, static_cast<int>(input_length), + 0, &misspelling_start, &misspelling_length, NULL); @@ -377,9 +380,7 @@ TEST_F(SpellCheckTest, SpellCheckSuggestions_EN_US) { {L"compitition", false, 0,0,L"competition"}, {L"conceed", false, 0,0,L"concede"}, {L"congradulate", false, 0,0,L"congratulate"}, - // TODO(pwicks): This fails as a result of 13432. - // Once that is fixed, uncomment this. - // {L"consciencious", false, 0,0,L"conscientious"}, + {L"consciencious", false, 0, 0, L"conscientious"}, {L"concious", false, 0,0,L"conscious"}, {L"concensus", false, 0,0,L"consensus"}, {L"contraversy", false, 0,0,L"controversy"}, @@ -452,9 +453,7 @@ TEST_F(SpellCheckTest, SpellCheckSuggestions_EN_US) { {L"imediately", false, 0,0,L"immediately"}, {L"incidently", false, 0,0,L"incidentally"}, {L"independant", false, 0,0,L"independent"}, - // TODO(pwicks): This fails as a result of 13432. - // Once that is fixed, uncomment this. - // {L"indispensible", false, 0,0,L"indispensable"}, + {L"indispensible", false, 0, 0, L"indispensable"}, {L"innoculate", false, 0,0,L"inoculate"}, {L"inteligence", false, 0,0,L"intelligence"}, {L"intresting", false, 0,0,L"interesting"}, @@ -533,9 +532,7 @@ TEST_F(SpellCheckTest, SpellCheckSuggestions_EN_US) { {L"proffesional", false, 0,0,L"professional"}, {L"professer", false, 0,0,L"professor"}, {L"promiss", false, 0,0,L"promise"}, - // TODO(pwicks): This fails as a result of 13432. - // Once that is fixed, uncomment this. - // {L"pronounciation", false, 0,0,L"pronunciation"}, + {L"pronounciation", false, 0, 0, L"pronunciation"}, {L"prufe", false, 0,0,L"proof"}, {L"psycology", false, 0,0,L"psychology"}, {L"publically", false, 0,0,L"publicly"}, @@ -631,6 +628,7 @@ TEST_F(SpellCheckTest, SpellCheckSuggestions_EN_US) { int misspelling_length; bool result = spell_checker->SpellCheckWord(kTestCases[i].input, static_cast<int>(input_length), + 0, &misspelling_start, &misspelling_length, &suggestions); @@ -899,6 +897,7 @@ TEST_F(SpellCheckTest, SpellCheckText) { int misspelling_length = 0; bool result = spell_checker->SpellCheckWord(kTestCases[i].input, static_cast<int>(input_length), + 0, &misspelling_start, &misspelling_length, NULL); @@ -940,6 +939,7 @@ TEST_F(SpellCheckTest, DISABLED_SpellCheckAddToDictionary_EN_US) { int misspelling_length; bool result = spell_checker->SpellCheckWord(kTestCases[i].word_to_add, static_cast<int>(input_length), + 0, &misspelling_start, &misspelling_length, &suggestions); @@ -964,6 +964,7 @@ TEST_F(SpellCheckTest, DISABLED_SpellCheckAddToDictionary_EN_US) { bool result = spell_checker_new->SpellCheckWord( kTestCases[i].word_to_add, static_cast<int>(input_length), + 0, &misspelling_start, &misspelling_length, &suggestions); @@ -1030,6 +1031,7 @@ TEST_F(SpellCheckTest, DISABLED_SpellCheckSuggestionsAddToDictionary_EN_US) { int misspelling_length; bool result = spell_checker->SpellCheckWord(kTestCasesToBeTested[i].input, static_cast<int>(input_length), + 0, &misspelling_start, &misspelling_length, &suggestions); @@ -1081,9 +1083,86 @@ TEST_F(SpellCheckTest, GetAutoCorrectionWord_EN_US) { std::wstring misspelled_word(kTestCases[i].input); std::wstring expected_autocorrect_word(kTestCases[i].expected_result); std::wstring autocorrect_word; - spell_checker->GetAutoCorrectionWord(misspelled_word, &autocorrect_word); + spell_checker->GetAutoCorrectionWord(misspelled_word, 0, &autocorrect_word); // Check for spelling. EXPECT_EQ(expected_autocorrect_word, autocorrect_word); } } + +#if defined(OS_MACOSX) +// Tests that words are properly ignored. Currently only enabled on OS X as it +// is the only platform to support ignoring words. Note that in this test, we +// supply a non-zero doc_tag, in order to test that ignored words are matched to +// the correct document. +TEST_F(SpellCheckTest, IgnoreWords_EN_US) { + static const struct { + // A misspelled word. + const wchar_t* input; + bool input_result; + } kTestCases[] = { + {L"teh",false}, + {L"moer", false}, + {L"watre",false}, + {L"noen", false}, + }; + + FilePath hunspell_directory = GetHunspellDirectory(); + ASSERT_FALSE(hunspell_directory.empty()); + + scoped_refptr<SpellChecker> spell_checker(new SpellChecker( + hunspell_directory, "en-US", NULL, FilePath())); + + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestCases); ++i) { + std::wstring word(kTestCases[i].input); + std::string misspelled_word = base::SysWideToUTF8(word); + std::vector<std::wstring> suggestions; + size_t input_length = 0; + if (kTestCases[i].input != NULL) { + input_length = wcslen(kTestCases[i].input); + } + int misspelling_start; + int misspelling_length; + + int doc_tag = SpellCheckerPlatform::GetDocumentTag(); + bool result = spell_checker->SpellCheckWord(kTestCases[i].input, + static_cast<int>(input_length), + doc_tag, + &misspelling_start, + &misspelling_length, + &suggestions); + + // The word should show up as misspelled. + EXPECT_EQ(kTestCases[i].input_result, result); + + // Ignore the word. + SpellCheckerPlatform::IgnoreWord(misspelled_word); + + // Spellcheck again. + result = spell_checker->SpellCheckWord(kTestCases[i].input, + static_cast<int>(input_length), + doc_tag, + &misspelling_start, + &misspelling_length, + &suggestions); + + // The word should now show up as correctly spelled. + EXPECT_EQ(!(kTestCases[i].input_result), result); + + // Close the docuemnt. Any words that we had previously ignored should no + // longer be ignored and thus should show up as misspelled. + SpellCheckerPlatform::CloseDocumentWithTag(doc_tag); + + // Spellcheck one more time. + result = spell_checker->SpellCheckWord(kTestCases[i].input, + static_cast<int>(input_length), + doc_tag, + &misspelling_start, + &misspelling_length, + &suggestions); + + // The word should now show be spelled wrong again + EXPECT_EQ(kTestCases[i].input_result, result); + } +} // Test IgnoreWords_EN_US +#endif // OS_MACOSX diff --git a/chrome/browser/spellchecker.cc b/chrome/browser/spellchecker.cc index b6e43fb..0a9f03e 100644 --- a/chrome/browser/spellchecker.cc +++ b/chrome/browser/spellchecker.cc @@ -533,7 +533,7 @@ bool SpellChecker::Initialize() { return false; } -void SpellChecker::GetAutoCorrectionWord(const std::wstring& word, +void SpellChecker::GetAutoCorrectionWord(const std::wstring& word, int tag, std::wstring* autocorrect_word) { autocorrect_word->clear(); if (!auto_spell_correct_turned_on_) @@ -560,7 +560,7 @@ void SpellChecker::GetAutoCorrectionWord(const std::wstring& word, // Check spelling. misspelling_start = misspelling_len = 0; - SpellCheckWord(misspelled_word, word_length, &misspelling_start, + SpellCheckWord(misspelled_word, word_length, tag, &misspelling_start, &misspelling_len, NULL); // Make decision: if only one swap produced a valid word, then we want to @@ -604,7 +604,7 @@ void SpellChecker::AddCustomWordsToHunspell() { // This function is a fall-back when the SpellcheckWordIterator class // returns a concatenated word which is not in the selected dictionary // (e.g. "in'n'out") but each word is valid. -bool SpellChecker::IsValidContraction(const string16& contraction) { +bool SpellChecker::IsValidContraction(const string16& contraction, int tag) { SpellcheckWordIterator word_iterator; word_iterator.Initialize(&character_attributes_, contraction.c_str(), contraction.length(), false); @@ -613,7 +613,7 @@ bool SpellChecker::IsValidContraction(const string16& contraction) { int word_start; int word_length; while (word_iterator.GetNextWord(&word, &word_start, &word_length)) { - if (!CheckSpelling(UTF16ToUTF8(word))) + if (!CheckSpelling(UTF16ToUTF8(word), tag)) return false; } return true; @@ -622,6 +622,7 @@ bool SpellChecker::IsValidContraction(const string16& contraction) { bool SpellChecker::SpellCheckWord( const wchar_t* in_word, int in_word_len, + int tag, int* misspelling_start, int* misspelling_len, std::vector<std::wstring>* optional_suggestions) { @@ -665,13 +666,13 @@ bool SpellChecker::SpellCheckWord( // Found a word (or a contraction) that the spellchecker can check the // spelling of. std::string encoded_word = UTF16ToUTF8(word); - bool word_ok = CheckSpelling(encoded_word); + bool word_ok = CheckSpelling(encoded_word, tag); if (word_ok) continue; // If the given word is a concatenated word of two or more valid words // (e.g. "hello:hello"), we should treat it as a valid word. - if (IsValidContraction(word)) + if (IsValidContraction(word, tag)) continue; *misspelling_start = word_start; @@ -739,12 +740,12 @@ void SpellChecker::AddWord(const std::wstring& word) { write_word_task->Run(); } -bool SpellChecker::CheckSpelling(const std::string& word_to_check) { +bool SpellChecker::CheckSpelling(const std::string& word_to_check, int tag) { bool word_correct = false; TimeTicks begin_time = TimeTicks::Now(); if (is_using_platform_spelling_engine_) { - word_correct = SpellCheckerPlatform::CheckSpelling(word_to_check); + word_correct = SpellCheckerPlatform::CheckSpelling(word_to_check, tag); } else { // |hunspell_->spell| returns 0 if the word is spelled correctly and // non-zero otherwsie. diff --git a/chrome/browser/spellchecker.h b/chrome/browser/spellchecker.h index fa1b156..48e4153 100644 --- a/chrome/browser/spellchecker.h +++ b/chrome/browser/spellchecker.h @@ -64,6 +64,8 @@ class SpellChecker : public base::RefCountedThreadSafe<SpellChecker>, // SpellCheck a word. // Returns true if spelled correctly, false otherwise. // If the spellchecker failed to initialize, always returns true. + // The |tag| parameter should either be a unique identifier for the document + // that the word came from (if the current platform requires it), or 0. // In addition, finds the suggested words for a given word // and puts them into |*optional_suggestions|. // If the word is spelled correctly, the vector is empty. @@ -71,6 +73,7 @@ class SpellChecker : public base::RefCountedThreadSafe<SpellChecker>, // Note that Doing suggest lookups can be slow. bool SpellCheckWord(const wchar_t* in_word, int in_word_len, + int tag, int* misspelling_start, int* misspelling_len, std::vector<std::wstring>* optional_suggestions); @@ -78,7 +81,7 @@ class SpellChecker : public base::RefCountedThreadSafe<SpellChecker>, // Find a possible correctly spelled word for a misspelled word. Computes an // empty string if input misspelled word is too long, there is ambiguity, or // the correct spelling cannot be determined. - void GetAutoCorrectionWord(const std::wstring& word, + void GetAutoCorrectionWord(const std::wstring& word, int tag, std::wstring* autocorrect_word); // Turn auto spell correct support ON or OFF. @@ -124,7 +127,7 @@ class SpellChecker : public base::RefCountedThreadSafe<SpellChecker>, // When called, relays the request to check the spelling to the proper // backend, either hunspell or a platform-specific backend. - bool CheckSpelling(const std::string& word_to_check); + bool CheckSpelling(const std::string& word_to_check, int tag); // When called, relays the request to fill the list with suggestions to // the proper backend, either hunspell or a platform-specific backend. @@ -144,7 +147,7 @@ class SpellChecker : public base::RefCountedThreadSafe<SpellChecker>, // Returns whether or not the given word is a contraction of valid words // (e.g. "word:word"). - bool IsValidContraction(const string16& word); + bool IsValidContraction(const string16& word, int tag); // Return the file name of the dictionary, including the path and the version // numbers. diff --git a/chrome/browser/spellchecker_linux.cc b/chrome/browser/spellchecker_linux.cc index 1452f74..1596b50 100644 --- a/chrome/browser/spellchecker_linux.cc +++ b/chrome/browser/spellchecker_linux.cc @@ -28,28 +28,33 @@ bool SpellCheckerProvidesPanel() { return false; } -bool SpellCheckerPanelVisible() { +bool SpellingPanelVisible() { return false; } -void Init() { -} +void ShowSpellingPanel(bool show) { } -void SetLanguage(const std::string& lang_to_set) { -} +void UpdateSpellingPanelWithMisspelledWord(const std::wstring& word) { } + +void Init() { } -bool CheckSpelling(const std::string& word_to_check) { +void SetLanguage(const std::string& lang_to_set) { } + +bool CheckSpelling(const std::string& word_to_check, int tag) { return false; } void FillSuggestionList(const std::string& wrong_word, - std::vector<std::wstring>* optional_suggestions) { -} + std::vector<std::wstring>* optional_suggestions) { } -void AddWord(const std::wstring& word) { -} +void AddWord(const std::wstring& word) { } -void RemoveWord(const std::wstring& word) { -} +void RemoveWord(const std::wstring& word) { } + +int GetDocumentTag() { return 0; } + +void IgnoreWord(const std::string& word) { } + +void CloseDocumentWithTag(int tag) { } } // namespace SpellCheckerPlatform diff --git a/chrome/browser/spellchecker_mac.mm b/chrome/browser/spellchecker_mac.mm index f9bfac6..4fe6458 100644 --- a/chrome/browser/spellchecker_mac.mm +++ b/chrome/browser/spellchecker_mac.mm @@ -7,11 +7,12 @@ #import <Cocoa/Cocoa.h> -#include "chrome/browser/spellchecker_common.h" -#include "chrome/browser/spellchecker_platform_engine.h" +#include "base/logging.h" #include "base/time.h" #include "base/histogram.h" #include "base/sys_string_conversions.h" +#include "chrome/browser/spellchecker_common.h" +#include "chrome/browser/spellchecker_platform_engine.h" using base::TimeTicks; namespace { @@ -92,9 +93,30 @@ bool SpellCheckerProvidesPanel() { return true; } -bool SpellCheckerPanelVisible() { - return [[[NSSpellChecker sharedSpellChecker] spellingPanel] - isVisible] ? true : false; +bool SpellingPanelVisible() { + // This should only be called from the main thread. + DCHECK([NSThread currentThread] == [NSThread mainThread]); + return [[[NSSpellChecker sharedSpellChecker] spellingPanel] isVisible]; +} + +void ShowSpellingPanel(bool show) { + if (show) { + [[[NSSpellChecker sharedSpellChecker] spellingPanel] + performSelectorOnMainThread:@selector(makeKeyAndOrderFront:) + withObject:nil + waitUntilDone:YES]; + } else { + [[[NSSpellChecker sharedSpellChecker] spellingPanel] + performSelectorOnMainThread:@selector(close) + withObject:nil + waitUntilDone:YES]; + } +} + +void UpdateSpellingPanelWithMisspelledWord(const std::wstring& word) { + NSString * word_to_display = base::SysWideToNSString(word); + [[NSSpellChecker sharedSpellChecker] + updateSpellingPanelWithMisspelledWord:word_to_display]; } void Init() { @@ -121,7 +143,11 @@ void SetLanguage(const std::string& lang_to_set) { [[NSSpellChecker sharedSpellChecker] setLanguage:NS_lang_to_set]; } -bool CheckSpelling(const std::string& word_to_check) { +static int last_seen_tag_; + +bool CheckSpelling(const std::string& word_to_check, int tag) { + last_seen_tag_ = tag; + // [[NSSpellChecker sharedSpellChecker] checkSpellingOfString] returns an // NSRange that we can look at to determine if a word is misspelled. NSRange spell_range = {0,0}; @@ -130,7 +156,9 @@ bool CheckSpelling(const std::string& word_to_check) { NSString* NS_word_to_check = base::SysUTF8ToNSString(word_to_check); // Check the spelling, starting at the beginning of the word. spell_range = [[NSSpellChecker sharedSpellChecker] - checkSpellingOfString:NS_word_to_check startingAt:0]; + checkSpellingOfString:NS_word_to_check startingAt:0 + language:nil wrap:NO inSpellDocumentWithTag:tag + wordCount:NULL]; // If the length of the misspelled word == 0, // then there is no misspelled word. @@ -165,5 +193,20 @@ void RemoveWord(const std::wstring& word) { NSString *word_to_remove = base::SysWideToNSString(word); [[NSSpellChecker sharedSpellChecker] unlearnWord:word_to_remove]; } + +int GetDocumentTag() { + NSInteger doc_tag = [NSSpellChecker uniqueSpellDocumentTag]; + return static_cast<int>(doc_tag); +} + +void IgnoreWord(const std::string& word) { + [[NSSpellChecker sharedSpellChecker] ignoreWord:base::SysUTF8ToNSString(word) + inSpellDocumentWithTag:last_seen_tag_]; +} + +void CloseDocumentWithTag(int tag) { + [[NSSpellChecker sharedSpellChecker] + closeSpellDocumentWithTag:static_cast<NSInteger>(tag)]; +} } // namespace SpellCheckerPlatform diff --git a/chrome/browser/spellchecker_platform_engine.h b/chrome/browser/spellchecker_platform_engine.h index ddfe64b..bf5eb94 100644 --- a/chrome/browser/spellchecker_platform_engine.h +++ b/chrome/browser/spellchecker_platform_engine.h @@ -26,7 +26,14 @@ bool SpellCheckerAvailable(); bool SpellCheckerProvidesPanel(); // Returns true if the platform spellchecker panel is visible. -bool SpellCheckerPanelVisible(); +bool SpellingPanelVisible(); + +// Shows the spelling panel if |show| is true and hides it if it is not. +void ShowSpellingPanel(bool show); + +// Changes the word show in the spelling panel to be |word|. Note that the +// spelling panel need not be displayed for this to work. +void UpdateSpellingPanelWithMisspelledWord(const std::wstring& word); // Do any initialization needed for spellchecker. void Init(); @@ -43,7 +50,7 @@ void SetLanguage(const std::string& lang_to_set); // Checks the spelling of the given string, using the platform-specific // spellchecker. Returns true if the word is spelled correctly. -bool CheckSpelling(const std::string& word_to_check); +bool CheckSpelling(const std::string& word_to_check, int tag); // Fills the given vector |optional_suggestions| with a number (up to // kMaxSuggestions, which is defined in spellchecker_common.h) of suggestions @@ -56,6 +63,21 @@ void AddWord(const std::wstring& word); // Remove a given word from the platform dictionary. void RemoveWord(const std::wstring& word); + +// Gets a unique tag to identify a document. Used in ignoring words. +int GetDocumentTag(); + +// Tells the platform spellchecker to ignore a word. This doesn't take a tag +// because in most of the situations in which it is called, the only way to know +// the tag for sure is to ask the renderer, which would mean blocking in the +// browser, so (on the mac, anyway) we remember the most recent tag and use +// it, since it should always be from the same document. +void IgnoreWord(const std::string& word); + +// Tells the platform spellchecker that a document associated with a tag has +// closed. Generally, this means that any ignored words associated with that +// document can now be forgotten. +void CloseDocumentWithTag(int tag); } #endif // CHROME_BROWSER_SPELLCHECKER_PLATFORM_ENGINE_H_ diff --git a/chrome/browser/spellchecker_win.cc b/chrome/browser/spellchecker_win.cc index 73db800..4fd2dfa 100644 --- a/chrome/browser/spellchecker_win.cc +++ b/chrome/browser/spellchecker_win.cc @@ -28,28 +28,33 @@ bool SpellCheckerProvidesPanel() { return false; } -bool SpellCheckerPanelVisible() { +bool SpellingPanelVisible() { return false; } -void Init() { -} +void ShowSpellingPanel(bool show) { } -void SetLanguage(const std::string& lang_to_set) { -} +void UpdateSpellingPanelWithMisspelledWord(const std::wstring& word) { } + +void Init() { } -bool CheckSpelling(const std::string& word_to_check) { +void SetLanguage(const std::string& lang_to_set) { } + +bool CheckSpelling(const std::string& word_to_check, int tag) { return false; } void FillSuggestionList(const std::string& wrong_word, - std::vector<std::wstring>* optional_suggestions) { -} + std::vector<std::wstring>* optional_suggestions) { } -void AddWord(const std::wstring& word) { -} +void AddWord(const std::wstring& word) { } -void RemoveWord(const std::wstring& word) { -} +void RemoveWord(const std::wstring& word) { } + +int GetDocumentTag() { return 0; } + +void IgnoreWord(const std::string& word) { } + +void CloseDocumentWithTag(int tag) { } } // namespace SpellCheckerPlatform diff --git a/chrome/browser/tab_contents/render_view_context_menu.cc b/chrome/browser/tab_contents/render_view_context_menu.cc index b86001a..2b4345a 100644 --- a/chrome/browser/tab_contents/render_view_context_menu.cc +++ b/chrome/browser/tab_contents/render_view_context_menu.cc @@ -19,6 +19,7 @@ #include "chrome/browser/profile.h" #include "chrome/browser/search_engines/template_url_model.h" #include "chrome/browser/spellchecker.h" +#include "chrome/browser/spellchecker_platform_engine.h" #include "chrome/browser/tab_contents/navigation_entry.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/common/chrome_switches.h" @@ -258,6 +259,15 @@ void RenderViewContextMenu::AppendEditableItems() { l10n_util::GetStringUTF16( IDS_CONTENT_CONTEXT_CHECK_SPELLING_OF_THIS_FIELD)); + // Add option for showing the spelling panel if the platfrom spellchecker + // supports it. + if (SpellCheckerPlatform::SpellCheckerAvailable() && + SpellCheckerPlatform::SpellCheckerProvidesPanel()) { + AppendCheckboxMenuItem(IDC_SPELLPANEL_TOGGLE, l10n_util::GetStringUTF16( + SpellCheckerPlatform::SpellingPanelVisible() ? + IDS_CONTENT_CONTEXT_HIDE_SPELLING_PANEL : + IDS_CONTENT_CONTEXT_SHOW_SPELLING_PANEL)); + } FinishSubMenu(); AppendSeparator(); @@ -700,6 +710,10 @@ void RenderViewContextMenu::ExecuteItemCommand(int id) { LANGUAGES_PAGE, profile_); break; + case IDC_SPELLPANEL_TOGGLE: + source_tab_contents_->render_view_host()->ToggleSpellPanel( + SpellCheckerPlatform::SpellingPanelVisible()); + break; case IDS_CONTENT_CONTEXT_ADDSEARCHENGINE: // Not implemented. default: break; |