High Level

There will be a context menu from which the display of the spelling panel can be toggled. This will tie into some methods in webkit that will make sure that the selection is in the right place and in sync with the panel. By catching the messages that the spelling panel sends we can also do the right things when the user asks to correct words, ignore words, move to the next misspelled word and learn words. Additionally, the language of the spellchecker can also be changed through the spelling panel.

Details

Toggling the Spelling Panel

Design document for the addition of the spelling panel to Chromium

  • Add a new define, IDC_SPELLING_PANEL_TOGGLE, to chrome_dll_resource.h.
  • Add code to RenderViewContextMenu::AppendEditableItems to check the state of the spelling panel and make the right decision. Note that this has to touch the function SpellCheckerPlatform::SpellingPanelVisible() which should only be called from the main thread (which this is, so it's ok).
  • Showing the spelling panel works as follows: RenderViewContextMenu::ExecuteCommand will need another case to handle the added define. It calls source_tab_contents_->render_view_host()->ToggleSpellPanel(), which in turn does Send(new ViewMsg_ToggleSpellPanel(routing_id(),bool)). The bool should be the current state of the spelling panel, which is cached on the webkit side to avoid an extra IPC call that would be difficult to execute, due to the limitations with SpellCheckerPlatform::SpellingPanelVisible(). This message is caught in RenderView, which caches the visibility and then calls ToggleSpellPanel on the focused frame. This call ends up at WebFrameImpl, which forwards the call to the webkit method Editor::showSpellingGuessPanel. From here, webkit does a few things and then calls advanceToNextMispelling, which calls client()->updateSpellingUIWithMisspelledWord(misspelledWord); which will eventually end up back in the browser due to an IPC call. We can update the panel using [[NSSpellChecker sharedSpellChecker] updateSpellingPanelWithMisspelledWord:nextMisspelledWord]. After that, client()->showSpellingUI(true) is called. This puts us back in the webkit glue code in editor_client_impl.cc. From here, we grab the current WebViewDelegate and call ShowSpellingUI. This call ends up in RenderView, since it implements WebViewDelegate, which finally does Send(new ViewHostMsg_ShowSpellingPanel(routing_id_,show)). This is caught in resource_message_filter.cc, which forwards the call to SpellCheckerPlatform::ShowSpellingPanel where we finally display the panel. Hiding the spelling Panel is a similar processs (i.e. we go through webkit and eventually receive a message back telling us to hid the spelling panel).

Spellchecking Words

  • advanceToNextMisspelling in webkit ensures that the currently misspelled word is selected. When the user clicks on the change button in the spelling correction panel, the panel sends a message up the responder chain. We catch this message (changeSpelling) in render_widget_host_view_mac.mm and interrogate the spelling panel (the sender) to find out what the new word is. We then send an IPC message to the renderer telling it to replace the selected word and advance to the next misspelling, the machinery for which already exists in webkit. The spelling panel will also send the checkSpelling message, although this is not very well documented. Anytime we receive this message, we should advance to the next misspelled word, which we can do using advanceToNextMisspelling.

The Find Next Button

  • When the Find Next button is clicked, the spelling panel sends just the checkSpelling message, so little additional work is needed to enable Find Next.

Learning Words

  • When the Learn Button is clicked, the spelling panel handles telling OS X to learn the word, but we still need to move to the next word and provide it with the next misspelling. Again, this is just a matter of catching the checkSpelling message.

Ignoring Words

  • In order to support ignoring words, we need to have unique document tags for every RenderView; this could be done at a more fine grain level, but this is how mainline webkit does it. Whenever a spellcheck request is generated in webkit, it asks for a document tag, which we can obtain from the browser through an IPC call (the actual tags are generated by [NSSpellChecker uniqueSpellDocumentTag]). This tag is stored in the RenderView and all spellchecking requests from webkit now bundle the tag. On platforms other than OS X, it is eventually ignored.
  • When the user clicks the Ignore button in the panel, we receive an ignoreSpelling message. We send this to SpellCheckerPlatform::IgnoreWord, where we can make the calls to the NSSpellChecker to ignore the word. However, there is a problem. We don't know what the tag of the document that we are in is. To solve this, we cache the document tag whenever we spellcheck a word and use that document tag.
  • When a RenderView is closed, it sends an IPC message to the Browser telling it that the document with it's tag has been closed. This lets us forget those words that we no longer need to ignore.

Unresolved Issues

  • The spelling panel displays Multilingual as an option for the spelling language, which is not currently supported by chromium.