diff options
author | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-27 00:20:51 +0000 |
---|---|---|
committer | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-27 00:20:51 +0000 |
commit | f5b16fed647e941aa66933178da85db2860d639b (patch) | |
tree | f00e9856c04aad3b558a140955e7674add33f051 /webkit/glue/editor_client_impl.cc | |
parent | 920c091ac3ee15079194c82ae8a7a18215f3f23c (diff) | |
download | chromium_src-f5b16fed647e941aa66933178da85db2860d639b.zip chromium_src-f5b16fed647e941aa66933178da85db2860d639b.tar.gz chromium_src-f5b16fed647e941aa66933178da85db2860d639b.tar.bz2 |
Add webkit to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@18 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/glue/editor_client_impl.cc')
-rw-r--r-- | webkit/glue/editor_client_impl.cc | 786 |
1 files changed, 786 insertions, 0 deletions
diff --git a/webkit/glue/editor_client_impl.cc b/webkit/glue/editor_client_impl.cc new file mode 100644 index 0000000..50545d6 --- /dev/null +++ b/webkit/glue/editor_client_impl.cc @@ -0,0 +1,786 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// The Mac interface forwards most of these commands to the application layer, +// and I'm not really sure what to do about most of them. + +#include "config.h" +#pragma warning(push, 0) +#include "Document.h" +#include "EditCommand.h" +#include "Editor.h" +#include "EventHandler.h" +#include "EventNames.h" +#include "HTMLInputElement.h" +#include "Frame.h" +#include "KeyboardEvent.h" +#include "PlatformKeyboardEvent.h" +#include "PlatformString.h" +#include "WebView.h" +#pragma warning(pop) + +#undef LOG + +#include "base/string_util.h" +#include "webkit/glue/editor_client_impl.h" +#include "webkit/glue/glue_util.h" +#include "webkit/glue/webkit_glue.h" +#include "webkit/glue/webview_impl.h" + +// The notImplemented() from NotImplemented.h is now being dragged in via +// webview_impl.h. We want the one from LogWin.h instead. +#undef notImplemented +#include "LogWin.h" + +// Arbitrary depth limit for the undo stack, to keep it from using +// unbounded memory. This is the maximum number of distinct undoable +// actions -- unbroken stretches of typed characters are coalesced +// into a single action. +static const int kMaximumUndoStackDepth = 1000; + +namespace { + +// Record an editor command from the keyDownEntries[] below. We ignore the +// Move* and Insert* commands because they're not that interesting. +void MaybeRecordCommand(WebViewDelegate* d, const char* command_name) { + if (!d) + return; + + const char* move_prefix = "Move"; + const char* insert_prefix = "Insert"; + const char* delete_prefix = "Delete"; + // Ignore all the Move*, Insert*, and Delete* commands. + if (0 == strncmp(command_name, move_prefix, sizeof(move_prefix)) || + 0 == strncmp(command_name, insert_prefix, sizeof(insert_prefix)) || + 0 == strncmp(command_name, delete_prefix, sizeof(delete_prefix))) { + return; + } + d->UserMetricsRecordComputedAction(UTF8ToWide(command_name)); +} + +} + +EditorClientImpl::EditorClientImpl(WebView* web_view) + : web_view_(static_cast<WebViewImpl*>(web_view)), + use_editor_delegate_(false), + in_redo_(false), + preserve_(false), + pending_inline_autocompleted_element_(NULL) { +} + +EditorClientImpl::~EditorClientImpl() { +} + +void EditorClientImpl::pageDestroyed() { + // Called by the Page (which owns the editor client) when the page is going + // away. This should cause us to delete ourselves, which is stupid. The page + // should just delete us when it's going away. Oh well. + delete this; +} + +bool EditorClientImpl::shouldShowDeleteInterface(WebCore::HTMLElement* elem) { + // Normally, we don't care to show WebCore's deletion UI, so we only enable + // it if in testing mode and the test specifically requests it by using this + // magic class name. + return webkit_glue::IsLayoutTestMode() && + elem->className() == "needsDeletionUI"; +} + +bool EditorClientImpl::smartInsertDeleteEnabled() { + if (use_editor_delegate_) { + WebViewDelegate* d = web_view_->delegate(); + if (d) + return d->SmartInsertDeleteEnabled(); + } + return true; +} + +bool EditorClientImpl::isContinuousSpellCheckingEnabled() { + // Spell check everything if possible. + // FIXME(brettw) This should be modified to do reasonable defaults depending + // on input type, and probably also allow the user to turn spellchecking on + // for individual fields. + return true; +} + +void EditorClientImpl::toggleContinuousSpellChecking() { + notImplemented(); +} + +bool EditorClientImpl::isGrammarCheckingEnabled() { + notImplemented(); + return false; +} + +void EditorClientImpl::toggleGrammarChecking() { + notImplemented(); +} + +int EditorClientImpl::spellCheckerDocumentTag() { + notImplemented(); + return 0; +} + +bool EditorClientImpl::isEditable() { + notImplemented(); + return false; +} + +bool EditorClientImpl::shouldBeginEditing(WebCore::Range* range) { + if (use_editor_delegate_) { + WebViewDelegate* d = web_view_->delegate(); + if (d) + return d->ShouldBeginEditing(web_view_, Describe(range)); + } + return true; +} + +bool EditorClientImpl::shouldEndEditing(WebCore::Range* range) { + if (use_editor_delegate_) { + WebViewDelegate* d = web_view_->delegate(); + if (d) + return d->ShouldEndEditing(web_view_, Describe(range)); + } + return true; +} + +bool EditorClientImpl::shouldInsertNode(WebCore::Node* node, + WebCore::Range* range, + WebCore::EditorInsertAction action) { + if (use_editor_delegate_) { + WebViewDelegate* d = web_view_->delegate(); + if (d) { + return d->ShouldInsertNode(web_view_, + Describe(node), + Describe(range), + Describe(action)); + } + } + return true; +} + +bool EditorClientImpl::shouldInsertText(WebCore::String text, + WebCore::Range* range, + WebCore::EditorInsertAction action) { + if (use_editor_delegate_) { + WebViewDelegate* d = web_view_->delegate(); + if (d) { + std::wstring wstr = webkit_glue::StringToStdWString(text); + return d->ShouldInsertText(web_view_, + wstr, + Describe(range), + Describe(action)); + } + } + return true; +} + + +bool EditorClientImpl::shouldDeleteRange(WebCore::Range* range) { + if (use_editor_delegate_) { + WebViewDelegate* d = web_view_->delegate(); + if (d) + return d->ShouldDeleteRange(web_view_, Describe(range)); + } + return true; +} + +void EditorClientImpl::PreserveSelection() { + preserve_ = true; +} + +bool EditorClientImpl::shouldChangeSelectedRange(WebCore::Range* fromRange, + WebCore::Range* toRange, + WebCore::EAffinity affinity, + bool stillSelecting) { + if (use_editor_delegate_) { + WebViewDelegate* d = web_view_->delegate(); + if (d) { + return d->ShouldChangeSelectedRange(web_view_, + Describe(fromRange), + Describe(toRange), + Describe(affinity), + stillSelecting); + } + } + // Have we been told to preserve the selection? + // (See comments for PreserveSelection in header). + if (preserve_) { + preserve_ = false; + return false; + } + return true; +} + +bool EditorClientImpl::shouldApplyStyle(WebCore::CSSStyleDeclaration* style, + WebCore::Range* range) { + if (use_editor_delegate_) { + WebViewDelegate* d = web_view_->delegate(); + if (d) + return d->ShouldApplyStyle(web_view_, Describe(style), Describe(range)); + } + return true; +} + +bool EditorClientImpl::shouldMoveRangeAfterDelete( + WebCore::Range* /*range*/, + WebCore::Range* /*rangeToBeReplaced*/) { + notImplemented(); + return true; +} + +void EditorClientImpl::didBeginEditing() { + if (use_editor_delegate_) { + WebViewDelegate* d = web_view_->delegate(); + if (d) + d->DidBeginEditing(); + } +} + +void EditorClientImpl::respondToChangedSelection() { + if (use_editor_delegate_) { + WebViewDelegate* d = web_view_->delegate(); + if (d) + d->DidChangeSelection(); + } +} + +void EditorClientImpl::respondToChangedContents() { + // Ugly Hack. (See also webkit bug #16976). + // Something is wrong with webcore's focusController in that when selection + // is set to a region within a text element when handling an input event, if + // you don't re-focus the node then it only _APPEARS_ to have successfully + // changed the selection (the UI "looks" right) but in reality there is no + // selection of text. And to make matters worse, you can't just re-focus it, + // you have to re-focus it in code executed after the entire event listener + // loop has finished; and hence here we are. Oh, and to make matters worse, + // this sequence of events _doesn't_ happen when you debug through the code + // -- in that case it works perfectly fine -- because swapping to the debugger + // causes the refocusing we artificially reproduce here. + // TODO (timsteele): Clean this up once root webkit problem is identified and + // the bug is patched. + if (pending_inline_autocompleted_element_) { + pending_inline_autocompleted_element_->blur(); + pending_inline_autocompleted_element_->focus(); + pending_inline_autocompleted_element_ = NULL; + } + + if (use_editor_delegate_) { + WebViewDelegate* d = web_view_->delegate(); + if (d) + d->DidChangeContents(); + } +} + +void EditorClientImpl::didEndEditing() { + if (use_editor_delegate_) { + WebViewDelegate* d = web_view_->delegate(); + if (d) + d->DidEndEditing(); + } +} + +void EditorClientImpl::didWriteSelectionToPasteboard() { + notImplemented(); +} + +void EditorClientImpl::didSetSelectionTypesForPasteboard() { + notImplemented(); +} + +void EditorClientImpl::registerCommandForUndo( + PassRefPtr<WebCore::EditCommand> command) { + if (undo_stack_.size() == kMaximumUndoStackDepth) + undo_stack_.pop_front(); // drop oldest item off the far end + if (!in_redo_) + redo_stack_.clear(); + undo_stack_.push_back(command); +} + +void EditorClientImpl::registerCommandForRedo( + PassRefPtr<WebCore::EditCommand> command) { + redo_stack_.push_back(command); +} + +void EditorClientImpl::clearUndoRedoOperations() { + undo_stack_.clear(); + redo_stack_.clear(); +} + +bool EditorClientImpl::canUndo() const { + return !undo_stack_.empty(); +} + +bool EditorClientImpl::canRedo() const { + return !redo_stack_.empty(); +} + +void EditorClientImpl::undo() { + if (canUndo()) { + RefPtr<WebCore::EditCommand> command(undo_stack_.back()); + undo_stack_.pop_back(); + command->unapply(); + // unapply will call us back to push this command onto the redo stack. + } +} + +void EditorClientImpl::redo() { + if (canRedo()) { + RefPtr<WebCore::EditCommand> command(redo_stack_.back()); + redo_stack_.pop_back(); + + ASSERT(!in_redo_); + in_redo_ = true; + command->reapply(); + // reapply will call us back to push this command onto the undo stack. + in_redo_ = false; + } +} + +// Get the distance we should go (in pixels) when doing a pageup/pagedown. +static int GetVerticalPageDistance(WebCore::KeyboardEvent* event) { + if (event->target()) { + WebCore::Node* node = event->target()->toNode(); + if (node && node->renderer()) + return node->renderer()->contentHeight(); + } + + return 0; +} + +// The below code was adapted from the WebKit file webview.cpp +// provided by Apple, Inc, and is subject to the following copyright +// notice and disclaimer. + +/* + * Copyright (C) 2006, 2007 Apple, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +static const unsigned CtrlKey = 1 << 0; +static const unsigned AltKey = 1 << 1; +static const unsigned ShiftKey = 1 << 2; + +// Keys with special meaning. These will be delegated to the editor using +// the execCommand() method +struct KeyDownEntry { + unsigned virtualKey; + unsigned modifiers; + const char* name; +}; + +struct KeyPressEntry { + unsigned charCode; + unsigned modifiers; + const char* name; +}; + +static const KeyDownEntry keyDownEntries[] = { + { VK_LEFT, 0, "MoveLeft" }, + { VK_LEFT, ShiftKey, "MoveLeftAndModifySelection" }, + { VK_LEFT, CtrlKey, "MoveWordLeft" }, + { VK_LEFT, CtrlKey | ShiftKey, "MoveWordLeftAndModifySelection" }, + { VK_RIGHT, 0, "MoveRight" }, + { VK_RIGHT, ShiftKey, "MoveRightAndModifySelection" }, + { VK_RIGHT, CtrlKey, "MoveWordRight" }, + { VK_RIGHT, CtrlKey | ShiftKey, "MoveWordRightAndModifySelection" }, + { VK_UP, 0, "MoveUp" }, + { VK_UP, ShiftKey, "MoveUpAndModifySelection" }, + { VK_PRIOR, ShiftKey, "MovePageUpAndModifySelection" }, + { VK_DOWN, 0, "MoveDown" }, + { VK_DOWN, ShiftKey, "MoveDownAndModifySelection" }, + { VK_NEXT, ShiftKey, "MovePageDownAndModifySelection" }, + { VK_PRIOR, 0, "MovePageUp" }, + { VK_NEXT, 0, "MovePageDown" }, + { VK_HOME, 0, "MoveToBeginningOfLine" }, + { VK_HOME, ShiftKey, "MoveToBeginningOfLineAndModifySelection" }, + { VK_HOME, CtrlKey, "MoveToBeginningOfDocument" }, + { VK_HOME, CtrlKey | ShiftKey, "MoveToBeginningOfDocumentAndModifySelection" }, + + { VK_END, 0, "MoveToEndOfLine" }, + { VK_END, ShiftKey, "MoveToEndOfLineAndModifySelection" }, + { VK_END, CtrlKey, "MoveToEndOfDocument" }, + { VK_END, CtrlKey | ShiftKey, "MoveToEndOfDocumentAndModifySelection" }, + + { VK_BACK, 0, "DeleteBackward" }, + { VK_BACK, ShiftKey, "DeleteBackward" }, + { VK_DELETE, 0, "DeleteForward" }, + { VK_BACK, CtrlKey, "DeleteWordBackward" }, + { VK_DELETE, CtrlKey, "DeleteWordForward" }, + + { 'B', CtrlKey, "ToggleBold" }, + { 'I', CtrlKey, "ToggleItalic" }, + { 'U', CtrlKey, "ToggleUnderline" }, + + { VK_ESCAPE, 0, "Cancel" }, + { VK_OEM_PERIOD, CtrlKey, "Cancel" }, + { VK_TAB, 0, "InsertTab" }, + { VK_TAB, ShiftKey, "InsertBacktab" }, + { VK_RETURN, 0, "InsertNewline" }, + { VK_RETURN, CtrlKey, "InsertNewline" }, + { VK_RETURN, AltKey, "InsertNewline" }, + { VK_RETURN, AltKey | ShiftKey, "InsertNewline" }, + { VK_RETURN, ShiftKey, "InsertLineBreak" }, + + { 'C', CtrlKey, "Copy" }, + { VK_INSERT, CtrlKey, "Copy" }, + { 'V', CtrlKey, "Paste" }, + { VK_INSERT, ShiftKey, "Paste" }, + { 'V', CtrlKey | ShiftKey, "PasteAndMatchStyle" }, + { 'X', CtrlKey, "Cut" }, + { VK_DELETE, ShiftKey, "Cut" }, + { 'A', CtrlKey, "SelectAll" }, + { 'Z', CtrlKey, "Undo" }, + { 'Z', CtrlKey | ShiftKey, "Redo" }, + { 'Y', CtrlKey, "Redo" }, +}; + +static const KeyPressEntry keyPressEntries[] = { + { '\t', 0, "InsertTab" }, + { '\t', ShiftKey, "InsertBacktab" }, + { '\r', 0, "InsertNewline" }, + { '\r', CtrlKey, "InsertNewline" }, + { '\r', ShiftKey, "InsertLineBreak" }, + { '\r', AltKey, "InsertNewline" }, + { '\r', AltKey | ShiftKey, "InsertNewline" }, +}; + +const char* EditorClientImpl::interpretKeyEvent( + const WebCore::KeyboardEvent* evt) { + const WebCore::PlatformKeyboardEvent* keyEvent = evt->keyEvent(); + if (!keyEvent) + return ""; + + static HashMap<int, const char*>* keyDownCommandsMap = 0; + static HashMap<int, const char*>* keyPressCommandsMap = 0; + + if (!keyDownCommandsMap) { + keyDownCommandsMap = new HashMap<int, const char*>; + keyPressCommandsMap = new HashMap<int, const char*>; + + for (unsigned i = 0; i < _countof(keyDownEntries); i++) { + keyDownCommandsMap->set( + keyDownEntries[i].modifiers << 16 | keyDownEntries[i].virtualKey, + keyDownEntries[i].name); + } + + for (unsigned i = 0; i < _countof(keyPressEntries); i++) { + keyPressCommandsMap->set( + keyPressEntries[i].modifiers << 16 | keyPressEntries[i].charCode, + keyPressEntries[i].name); + } + } + + unsigned modifiers = 0; + if (keyEvent->shiftKey()) + modifiers |= ShiftKey; + if (keyEvent->altKey()) + modifiers |= AltKey; + if (keyEvent->ctrlKey()) + modifiers |= CtrlKey; + + if (evt->type() == WebCore::EventNames::keydownEvent) { + int mapKey = modifiers << 16 | evt->keyCode(); + return mapKey ? keyDownCommandsMap->get(mapKey) : 0; + } + + int mapKey = modifiers << 16 | evt->charCode(); + return mapKey ? keyPressCommandsMap->get(mapKey) : 0; +} + +bool EditorClientImpl::handleEditingKeyboardEvent( + WebCore::KeyboardEvent* evt) { + const WebCore::PlatformKeyboardEvent* keyEvent = evt->keyEvent(); + // do not treat this as text input if it's a system key event + if (!keyEvent || keyEvent->isSystemKey()) + return false; + + WebCore::Frame* frame = evt->target()->toNode()->document()->frame(); + if (!frame) + return false; + + const char* command_name = interpretKeyEvent(evt); + WebCore::Editor::Command command = frame->editor()->command(command_name); + + if (keyEvent->type() == WebCore::PlatformKeyboardEvent::RawKeyDown) { + // WebKit doesn't have enough information about mode to decide how + // commands that just insert text if executed via Editor should be treated, + // so we leave it upon WebCore to either handle them immediately + // (e.g. Tab that changes focus) or let a keypress event be generated + // (e.g. Tab that inserts a Tab character, or Enter). + if (command.isTextInsertion() || !command_name) + return false; + if (command.execute(evt)) { + WebViewDelegate* d = web_view_->delegate(); + MaybeRecordCommand(d, command_name); + return true; + } + return false; + } + + if (command.execute(evt)) { + WebViewDelegate* d = web_view_->delegate(); + MaybeRecordCommand(d, command_name); + return true; + } + + if (evt->keyEvent()->text().length() == 1) { + UChar ch = evt->keyEvent()->text()[0]; + + // Don't insert null or control characters as they can result in + // unexpected behaviour + if (ch < ' ') + return false; + } + + return frame->editor()->insertText(evt->keyEvent()->text(), evt); +} + +// +// End of code block subject to Apple, Inc. copyright +// + +void EditorClientImpl::handleKeyboardEvent(WebCore::KeyboardEvent* evt) { + if (handleEditingKeyboardEvent(evt)) + evt->setDefaultHandled(); +} + +void EditorClientImpl::handleInputMethodKeydown(WebCore::KeyboardEvent* keyEvent) { + notImplemented(); +} + +void EditorClientImpl::textFieldDidBeginEditing(WebCore::Element*) { + notImplemented(); +} + +void EditorClientImpl::textFieldDidEndEditing(WebCore::Element*) { + // Notification that focus was lost. + // Be careful with this, it's also sent when the page is being closed. + notImplemented(); +} + +void EditorClientImpl::textDidChangeInTextField(WebCore::Element* element) { + // Track the element so we can blur/focus it in respondToChangedContents + // so that the selected range is properly set. (See respondToChangedContents). + if (static_cast<WebCore::HTMLInputElement*>(element)->autofilled()) + pending_inline_autocompleted_element_ = element; +} + +bool EditorClientImpl::doTextFieldCommandFromEvent(WebCore::Element*, + WebCore::KeyboardEvent*) { + // The Mac code appears to use this method as a hook to implement special + // keyboard commands specific to Safari's auto-fill implementation. We + // just return false to allow the default action. + return false; +} + +void EditorClientImpl::textWillBeDeletedInTextField(WebCore::Element*) { + notImplemented(); +} + +void EditorClientImpl::textDidChangeInTextArea(WebCore::Element*) { + notImplemented(); +} + +void EditorClientImpl::ignoreWordInSpellDocument(const WebCore::String&) { + notImplemented(); +} + +void EditorClientImpl::learnWord(const WebCore::String&) { + notImplemented(); +} + +void EditorClientImpl::checkSpellingOfString(const UChar* str, int length, + int* misspellingLocation, + int* misspellingLength) { + // SpellCheckWord will write (0, 0) into the output vars, which is what our + // caller expects if the word is spelled correctly. + int spell_location = -1; + int spell_length = 0; + WebViewDelegate* d = web_view_->delegate(); + if (web_view_->FocusedFrameNeedsSpellchecking() && d) { + std::wstring word(str, length); + d->SpellCheck(word, spell_location, spell_length); + } else { + spell_location = 0; + spell_length = 0; + } + + // Note: the Mac code checks if the pointers are NULL before writing to them, + // so we do too. + if (misspellingLocation) + *misspellingLocation = spell_location; + if (misspellingLength) + *misspellingLength = spell_length; +} + +void EditorClientImpl::checkGrammarOfString(const UChar*, int length, + WTF::Vector<WebCore::GrammarDetail>&, + int* badGrammarLocation, + int* badGrammarLength) { + notImplemented(); + if (badGrammarLocation) + *badGrammarLocation = 0; + if (badGrammarLength) + *badGrammarLength = 0; +} + +void EditorClientImpl::updateSpellingUIWithGrammarString(const WebCore::String&, + const WebCore::GrammarDetail& detail) { + notImplemented(); +} + +void EditorClientImpl::updateSpellingUIWithMisspelledWord(const WebCore::String&) { + notImplemented(); +} + +void EditorClientImpl::showSpellingUI(bool show) { + notImplemented(); +} + +bool EditorClientImpl::spellingUIIsShowing() { + return false; +} + +void EditorClientImpl::getGuessesForWord(const WebCore::String&, + WTF::Vector<WebCore::String>& guesses) { + notImplemented(); +} + +void EditorClientImpl::setInputMethodState(bool enabled) { + WebViewDelegate* d = web_view_->delegate(); + if (d) { + d->SetInputMethodState(enabled); + } +} + + +std::wstring EditorClientImpl::DescribeOrError(int number, + WebCore::ExceptionCode ec) { + if (ec) + return L"ERROR"; + + wchar_t buffer[128]; + _itow_s(number, buffer, arraysize(buffer), 10); + return std::wstring(buffer); +} + +std::wstring EditorClientImpl::DescribeOrError(WebCore::Node* node, + WebCore::ExceptionCode ec) { + if (ec) + return L"ERROR"; + + return Describe(node); +} + +// These Describe() functions match the output expected by the layout tests. +std::wstring EditorClientImpl::Describe(WebCore::Range* range) { + if (range) { + WebCore::ExceptionCode exception = 0; + std::wstring str = L"range from "; + int offset = range->startOffset(exception); + str.append(DescribeOrError(offset, exception)); + str.append(L" of "); + WebCore::Node* container = range->startContainer(exception); + str.append(DescribeOrError(container, exception)); + str.append(L" to "); + offset = range->endOffset(exception); + str.append(DescribeOrError(offset, exception)); + str.append(L" of "); + container = range->endContainer(exception); + str.append(DescribeOrError(container, exception)); + return str; + } + return L"(null)"; +} + +// See comment for Describe(), above. +std::wstring EditorClientImpl::Describe(WebCore::Node* node) { + if (node) { + std::wstring str = webkit_glue::StringToStdWString(node->nodeName()); + WebCore::Node* parent = node->parentNode(); + if (parent) { + str.append(L" > "); + str.append(Describe(parent)); + } + return str; + } + return L"(null)"; +} + +// See comment for Describe(), above. +std::wstring EditorClientImpl::Describe(WebCore::EditorInsertAction action) { + switch (action) { + case WebCore::EditorInsertActionTyped: + return L"WebViewInsertActionTyped"; + case WebCore::EditorInsertActionPasted: + return L"WebViewInsertActionPasted"; + case WebCore::EditorInsertActionDropped: + return L"WebViewInsertActionDropped"; + } + return L"(UNKNOWN ACTION)"; +} + +// See comment for Describe(), above. +std::wstring EditorClientImpl::Describe(WebCore::EAffinity affinity) { + switch (affinity) { + case WebCore::UPSTREAM: + return L"NSSelectionAffinityUpstream"; + case WebCore::DOWNSTREAM: + return L"NSSelectionAffinityDownstream"; + } + return L"(UNKNOWN AFFINITY)"; +} + +std::wstring EditorClientImpl::Describe(WebCore::CSSStyleDeclaration* style) { + // TODO(pamg): Implement me. It's not clear what WebKit produces for this + // (their [style description] method), and none of the layout tests provide + // an example. But because none of them use it, it's not yet important. + return std::wstring(); +} |