summaryrefslogtreecommitdiffstats
path: root/webkit/glue/editor_client_impl.cc
diff options
context:
space:
mode:
authorinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-27 00:20:51 +0000
committerinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-27 00:20:51 +0000
commitf5b16fed647e941aa66933178da85db2860d639b (patch)
treef00e9856c04aad3b558a140955e7674add33f051 /webkit/glue/editor_client_impl.cc
parent920c091ac3ee15079194c82ae8a7a18215f3f23c (diff)
downloadchromium_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.cc786
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();
+}