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 | |
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
28 files changed, 509 insertions, 80 deletions
diff --git a/chrome/app/chrome_dll_resource.h b/chrome/app/chrome_dll_resource.h index 932ab01..769e4cc 100644 --- a/chrome/app/chrome_dll_resource.h +++ b/chrome/app/chrome_dll_resource.h @@ -192,6 +192,7 @@ #define IDC_SPELLCHECK_LANGUAGES_LAST 41106 #define IDC_CHECK_SPELLING_OF_THIS_FIELD 41107 #define IDC_SYNC_BOOKMARKS 41108 +#define IDC_SPELLPANEL_TOGGLE 41109 // Next default values for new objects // #ifdef APSTUDIO_INVOKED diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 8adef54..6537f04 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -467,6 +467,12 @@ each locale. aa1 --> <message name="IDS_CONTENT_CONTEXT_CHECK_SPELLING_OF_THIS_FIELD" desc="The name of the Check the spelling of this field command in the content area context menu"> &Check the spelling of this field </message> + <message name="IDS_CONTENT_CONTEXT_SHOW_SPELLING_PANEL" desc="The name of the Show Spelling Panel command in the content area context menu"> + &Show Spelling Panel + </message> + <message name="IDS_CONTENT_CONTEXT_HIDE_SPELLING_PANEL" desc="The name of the Hide Spelling Panel command in the content area context menu"> + &Hide Spelling Panel + </message> <message name="IDS_CONTENT_CONTEXT_SELECTALL" desc="The name of the Select All command in the content area context menu"> Select &all </message> 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; diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h index 22f273d..4a2e5b0 100644 --- a/chrome/common/render_messages_internal.h +++ b/chrome/common/render_messages_internal.h @@ -184,6 +184,11 @@ IPC_BEGIN_MESSAGES(View) IPC_MESSAGE_ROUTED0(ViewMsg_ToggleSpellCheck) IPC_MESSAGE_ROUTED0(ViewMsg_Delete) IPC_MESSAGE_ROUTED0(ViewMsg_SelectAll) + IPC_MESSAGE_ROUTED1(ViewMsg_ToggleSpellPanel, bool) + + // 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. + IPC_MESSAGE_ROUTED0(ViewMsg_AdvanceToNextMisspelling) // Copies the image at location x, y to the clipboard (if there indeed is an // image at that location). @@ -928,13 +933,34 @@ IPC_BEGIN_MESSAGES(ViewHost) std::string /* actual mime type for url */) // Requests spellcheck for a word. - IPC_SYNC_MESSAGE_ROUTED1_2(ViewHostMsg_SpellCheck, + IPC_SYNC_MESSAGE_ROUTED2_2(ViewHostMsg_SpellCheck, std::wstring /* word to check */, + int /* document tag*/, int /* misspell location */, int /* misspell length */) - IPC_SYNC_MESSAGE_ROUTED1_1(ViewHostMsg_GetAutoCorrectWord, + // Asks the browser for a unique document tag. + IPC_SYNC_MESSAGE_ROUTED0_1(ViewHostMsg_GetDocumentTag, + int /* the tag */) + + + // This message tells the spellchecker that a document, identified by an int + // tag, has been closed and all of the ignored words for that document can be + // forgotten. + IPC_MESSAGE_ROUTED1(ViewHostMsg_DocumentWithTagClosed, + int /* the tag */) + + // Tells the browser to display or not display the SpellingPanel + IPC_MESSAGE_ROUTED1(ViewHostMsg_ShowSpellingPanel, + bool /* if true, then show it, otherwise hide it*/) + + // Tells the browser to update the spelling panel with the given word. + IPC_MESSAGE_ROUTED1(ViewHostMsg_UpdateSpellingPanelWithMisspelledWord, + std::wstring /* the word to update the panel with */) + + IPC_SYNC_MESSAGE_ROUTED2_1(ViewHostMsg_GetAutoCorrectWord, std::wstring /* word to check */, + int /* tag for the document containg the word */, std::wstring /* autocorrected word */) // Initiate a download based on user actions like 'ALT+click'. diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc index e91936e..e99f961 100644 --- a/chrome/renderer/render_view.cc +++ b/chrome/renderer/render_view.cc @@ -212,7 +212,9 @@ RenderView::RenderView(RenderThreadBase* render_thread, determine_page_text_after_loading_stops_(false), view_type_(ViewType::INVALID), browser_window_id_(-1), - last_top_level_navigation_page_id_(-1), + last_top_level_navigation_page_id_(-1), + has_spell_checker_document_tag_(false), + document_tag_(0), webkit_preferences_(webkit_preferences) { Singleton<RenderViewSet>()->render_view_set_.insert(this); } @@ -222,6 +224,9 @@ RenderView::~RenderView() { if (decrement_shared_popup_at_destruction_) shared_popup_counter_->data--; + // Tell the spellchecker that the document is closed. + Send(new ViewHostMsg_DocumentWithTagClosed(routing_id_, document_tag_)); + render_thread_->RemoveFilter(audio_message_filter_); } @@ -346,6 +351,9 @@ void RenderView::OnMessageReceived(const IPC::Message& message) { IPC_MESSAGE_HANDLER(ViewMsg_Copy, OnCopy) IPC_MESSAGE_HANDLER(ViewMsg_Paste, OnPaste) IPC_MESSAGE_HANDLER(ViewMsg_Replace, OnReplace) + IPC_MESSAGE_HANDLER(ViewMsg_ToggleSpellPanel, OnToggleSpellPanel) + IPC_MESSAGE_HANDLER(ViewMsg_AdvanceToNextMisspelling, + OnAdvanceToNextMisspelling) IPC_MESSAGE_HANDLER(ViewMsg_ToggleSpellCheck, OnToggleSpellCheck) IPC_MESSAGE_HANDLER(ViewMsg_Delete, OnDelete) IPC_MESSAGE_HANDLER(ViewMsg_SelectAll, OnSelectAll) @@ -828,6 +836,23 @@ void RenderView::OnReplace(const std::wstring& text) { webview()->GetFocusedFrame()->replaceSelection(WideToUTF16Hack(text)); } +void RenderView::OnAdvanceToNextMisspelling() { + if (!webview()) + return; + webview()->GetFocusedFrame()->executeCommand( + WebString::fromUTF8("AdvanceToNextMisspelling")); +} + +void RenderView::OnToggleSpellPanel(bool is_currently_visible) { + if (!webview()) + return; + // We need to tell the webView whether the spelling panel is visible or not so + // that it won't need to make ipc calls later. + webview()->SetSpellingPanelVisibility(is_currently_visible); + webview()->GetFocusedFrame()->executeCommand( + WebString::fromUTF8("ToggleSpellPanel")); +} + void RenderView::OnToggleSpellCheck() { if (!webview()) return; @@ -2520,24 +2545,45 @@ bool RenderView::WasOpenedByUserGesture() const { return opened_by_user_gesture_; } -void RenderView::SpellCheck(const std::wstring& word, int* misspell_location, - int* misspell_length) { - Send(new ViewHostMsg_SpellCheck(routing_id_, word, misspell_location, - misspell_length)); +void RenderView::SpellCheck(const std::wstring& word, int tag, + int* misspell_location, + int* misspell_length) { + Send(new ViewHostMsg_SpellCheck(routing_id_, word, tag, + misspell_location, misspell_length)); } std::wstring RenderView::GetAutoCorrectWord( - const std::wstring& misspelled_word) { + const std::wstring& misspelled_word, int tag) { std::wstring autocorrect_word; const CommandLine& command_line = *CommandLine::ForCurrentProcess(); if (command_line.HasSwitch(switches::kAutoSpellCorrect)) { - Send(new ViewHostMsg_GetAutoCorrectWord(routing_id_, misspelled_word, + Send(new ViewHostMsg_GetAutoCorrectWord(routing_id_, misspelled_word, tag, &autocorrect_word)); } return autocorrect_word; } +void RenderView::ShowSpellingUI(bool show) { + Send(new ViewHostMsg_ShowSpellingPanel(routing_id_, show)); +} + +int RenderView::SpellCheckerDocumentTag() { + if (!has_spell_checker_document_tag_) { + // Make the call to get the tag. + int tag; + Send(new ViewHostMsg_GetDocumentTag(routing_id_, &tag)); + document_tag_ = tag; + has_spell_checker_document_tag_ = true; + } + return document_tag_; +} + +void RenderView::UpdateSpellingUIWithMisspelledWord(const std::wstring& word) { + Send(new ViewHostMsg_UpdateSpellingPanelWithMisspelledWord( + routing_id_, word)); +} + void RenderView::ScriptedPrint(WebFrame* frame) { DCHECK(webview()); if (webview()) { diff --git a/chrome/renderer/render_view.h b/chrome/renderer/render_view.h index 3274d44..b094f30 100644 --- a/chrome/renderer/render_view.h +++ b/chrome/renderer/render_view.h @@ -321,9 +321,13 @@ class RenderView : public RenderWidget, const WebKit::WebRect& selection); virtual bool WasOpenedByUserGesture() const; virtual void FocusAccessibilityObject(WebCore::AccessibilityObject* acc_obj); - virtual void SpellCheck(const std::wstring& word, int* misspell_location, + virtual void SpellCheck(const std::wstring& word, int tag, + int* misspell_location, int* misspell_length); - virtual std::wstring GetAutoCorrectWord(const std::wstring& word); + virtual std::wstring GetAutoCorrectWord(const std::wstring& word, int tag); + virtual void UpdateSpellingUIWithMisspelledWord(const std::wstring& word); + virtual void ShowSpellingUI(bool show); + virtual int SpellCheckerDocumentTag(); virtual void ScriptedPrint(WebKit::WebFrame* frame); virtual void UserMetricsRecordAction(const std::wstring& action); virtual void DnsPrefetch(const std::vector<std::string>& host_names); @@ -529,6 +533,8 @@ class RenderView : public RenderWidget, void OnCopy(); void OnPaste(); void OnReplace(const std::wstring& text); + void OnAdvanceToNextMisspelling(); + void OnToggleSpellPanel(bool is_currently_visible); void OnToggleSpellCheck(); void OnDelete(); void OnSelectAll(); @@ -894,6 +900,12 @@ class RenderView : public RenderWidget, // page id for the last navigation sent to the browser. int32 last_top_level_navigation_page_id_; + // True if the current RenderView has been assigned a document tag. + bool has_spell_checker_document_tag_; + + // Document tag for this RenderView. + int document_tag_; + // The settings this render view initialized WebKit with. WebPreferences webkit_preferences_; diff --git a/webkit/glue/editor_client_impl.cc b/webkit/glue/editor_client_impl.cc index a090eb7..f7d2561 100644 --- a/webkit/glue/editor_client_impl.cc +++ b/webkit/glue/editor_client_impl.cc @@ -152,7 +152,13 @@ void EditorClientImpl::toggleGrammarChecking() { } int EditorClientImpl::spellCheckerDocumentTag() { +#if defined(OS_MACOSX) + WebViewDelegate* d = web_view_->delegate(); + if (d) + return d->SpellCheckerDocumentTag(); +#else NOTIMPLEMENTED(); +#endif // OS_MACOSX return 0; } @@ -838,7 +844,8 @@ void EditorClientImpl::checkSpellingOfString(const UChar* str, int length, if (isContinuousSpellCheckingEnabled() && d) { std::wstring word = webkit_glue::StringToStdWString(WebCore::String(str, length)); - d->SpellCheck(word, &spell_location, &spell_length); + d->SpellCheck(word, spellCheckerDocumentTag(), + &spell_location, &spell_length); } else { spell_location = 0; spell_length = 0; @@ -867,7 +874,8 @@ WebCore::String EditorClientImpl::getAutoCorrectSuggestionForMisspelledWord( return WebCore::String(); } - std::wstring autocorrect_word = d->GetAutoCorrectWord(word); + std::wstring autocorrect_word = + d->GetAutoCorrectWord(word, spellCheckerDocumentTag()); return webkit_glue::StdWStringToString(autocorrect_word); } @@ -887,16 +895,28 @@ void EditorClientImpl::updateSpellingUIWithGrammarString(const WebCore::String&, NOTIMPLEMENTED(); } -void EditorClientImpl::updateSpellingUIWithMisspelledWord(const WebCore::String&) { - NOTIMPLEMENTED(); +void EditorClientImpl::updateSpellingUIWithMisspelledWord( + const WebCore::String& misspelled_word) { + std::wstring word = webkit_glue::StringToStdWString(misspelled_word); + WebViewDelegate* d = web_view_->delegate(); + if (d) { + d->UpdateSpellingUIWithMisspelledWord(word); + } } void EditorClientImpl::showSpellingUI(bool show) { - NOTIMPLEMENTED(); + WebViewDelegate* d = web_view_->delegate(); + if (d) { + d->ShowSpellingUI(show); + } } bool EditorClientImpl::spellingUIIsShowing() { - return false; + // SpellingPanel visibility is stored in the web_view_ every time a toggle + // message is sent from the browser. If we were to send a message to the + // browser and ask for the visibility, then we run into problems accessing + // cocoa methods on the UI thread. + return web_view_->GetSpellingPanelVisibility(); } void EditorClientImpl::getGuessesForWord(const WebCore::String&, diff --git a/webkit/glue/webframe_impl.cc b/webkit/glue/webframe_impl.cc index 7521532..e52075c 100644 --- a/webkit/glue/webframe_impl.cc +++ b/webkit/glue/webframe_impl.cc @@ -973,6 +973,12 @@ bool WebFrameImpl::executeCommand(const WebString& name) { rv = frame()->editor()->command(AtomicString("BackwardDelete")).execute(); } else if (EqualsASCII(command, "DeleteForward")) { rv = frame()->editor()->command(AtomicString("ForwardDelete")).execute(); + } else if (EqualsASCII(command, "AdvanceToNextMisspelling")) { + // False must be passed here, or the currently selected word will never be + // skipped. + frame()->editor()->advanceToNextMisspelling(false); + } else if (EqualsASCII(command, "ToggleSpellPanel")) { + frame()->editor()->showSpellingGuessPanel(); } else { rv = frame()->editor()->command(AtomicString(command.c_str())).execute(); } diff --git a/webkit/glue/webview.h b/webkit/glue/webview.h index 0cd33fc..db4e6fb 100644 --- a/webkit/glue/webview.h +++ b/webkit/glue/webview.h @@ -243,6 +243,9 @@ class WebView : public WebKit::WebWidget { virtual void SetIsTransparent(bool is_transparent) = 0; virtual bool GetIsTransparent() const = 0; + virtual void SetSpellingPanelVisibility(bool is_visible) = 0; + virtual bool GetSpellingPanelVisibility() = 0; + // Performs an action from a context menu for the node at the given // location. virtual void MediaPlayerActionAt(int x, diff --git a/webkit/glue/webview_delegate.h b/webkit/glue/webview_delegate.h index 99d9be36..3bbdf02 100644 --- a/webkit/glue/webview_delegate.h +++ b/webkit/glue/webview_delegate.h @@ -729,17 +729,28 @@ class WebViewDelegate : virtual public WebKit::WebWidgetClient { // indices (inclusive) will be filled with the offsets of the boundary of the // word within the given buffer. The out pointers must be specified. If the // word is correctly spelled (returns true), they will be set to (0,0). - virtual void SpellCheck(const std::wstring& word, int* misspell_location, + virtual void SpellCheck(const std::wstring& word, int tag, + int* misspell_location, int* misspell_length) { *misspell_location = *misspell_length = 0; } // Computes an auto correct word for a misspelled word. If no word is found, // empty string is computed. - virtual std::wstring GetAutoCorrectWord(const std::wstring& misspelled_word) { + virtual std::wstring GetAutoCorrectWord(const std::wstring& misspelled_word, + int tag) { return std::wstring(); } + // Returns the document tag for the current WebView. + virtual int SpellCheckerDocumentTag() { return 0; } + + // Switches the spelling panel to be displayed or not based on |show|. + virtual void ShowSpellingUI(bool show) { } + + // Update the spelling panel with the |word|. + virtual void UpdateSpellingUIWithMisspelledWord(const std::wstring& word) { } + // Asks the user to print the page or a specific frame. Called in response to // a window.print() call. virtual void ScriptedPrint(WebKit::WebFrame* frame) { } diff --git a/webkit/glue/webview_impl.cc b/webkit/glue/webview_impl.cc index f3cf268..effb17d 100644 --- a/webkit/glue/webview_impl.cc +++ b/webkit/glue/webview_impl.cc @@ -1934,3 +1934,11 @@ HitTestResult WebViewImpl::HitTestResultForWindowPos(const IntPoint& pos) { return page_->mainFrame()->eventHandler()-> hitTestResultAtPoint(doc_point, false); } + +void WebViewImpl::SetSpellingPanelVisibility(bool is_visible) { + spelling_panel_is_visible_ = is_visible; +} + +bool WebViewImpl::GetSpellingPanelVisibility() { + return spelling_panel_is_visible_; +} diff --git a/webkit/glue/webview_impl.h b/webkit/glue/webview_impl.h index 3c753ac..7bc66e9 100644 --- a/webkit/glue/webview_impl.h +++ b/webkit/glue/webview_impl.h @@ -242,6 +242,9 @@ class WebViewImpl : public WebView, public base::RefCounted<WebViewImpl> { // the underlying Node for them. WebCore::Node* GetNodeForWindowPos(int x, int y); + virtual void SetSpellingPanelVisibility(bool is_visible); + virtual bool GetSpellingPanelVisibility(); + #if ENABLE(NOTIFICATIONS) // Returns the provider of desktop notifications. WebKit::NotificationPresenterImpl* GetNotificationPresenter(); @@ -394,6 +397,9 @@ class WebViewImpl : public WebView, public base::RefCounted<WebViewImpl> { // Whether the webview is rendering transparently. bool is_transparent_; + // Whether the spelling panel is currently being displayed or not. + bool spelling_panel_is_visible_; + // Inspector settings. std::wstring inspector_settings_; |