2 * Copyright (C) 2006, 2007 Apple, Inc. All rights reserved.
3 * Copyright (C) 2010 Google, Inc. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include "EditorClientImpl.h"
31 #include "EditCommand.h"
33 #include "EventHandler.h"
34 #include "EventNames.h"
36 #include "HTMLInputElement.h"
37 #include "HTMLNames.h"
38 #include "KeyboardCodes.h"
39 #include "KeyboardEvent.h"
40 #include "PlatformKeyboardEvent.h"
41 #include "PlatformString.h"
42 #include "RenderObject.h"
44 #include "DOMUtilitiesPrivate.h"
45 #include "WebEditingAction.h"
46 #include "WebElement.h"
47 #include "WebFrameImpl.h"
49 #include "WebInputElement.h"
50 #include "WebInputEventConversion.h"
52 #include "WebPasswordAutocompleteListener.h"
54 #include "WebTextAffinity.h"
55 #include "WebViewClient.h"
56 #include "WebViewImpl.h"
58 using namespace WebCore;
62 // Arbitrary depth limit for the undo stack, to keep it from using
63 // unbounded memory. This is the maximum number of distinct undoable
64 // actions -- unbroken stretches of typed characters are coalesced
65 // into a single action.
66 static const size_t maximumUndoStackDepth = 1000;
68 // The size above which we stop triggering autofill for an input text field
69 // (so to avoid sending long strings through IPC).
70 static const size_t maximumTextSizeForAutofill = 1000;
72 EditorClientImpl::EditorClientImpl(WebViewImpl* webview)
75 , m_backspaceOrDeletePressed(false)
76 , m_spellCheckThisFieldStatus(SpellCheckAutomatic)
77 , m_autofillTimer(this, &EditorClientImpl::doAutofill)
81 EditorClientImpl::~EditorClientImpl()
85 void EditorClientImpl::pageDestroyed()
87 // Our lifetime is bound to the WebViewImpl.
90 bool EditorClientImpl::shouldShowDeleteInterface(HTMLElement* elem)
92 // Normally, we don't care to show WebCore's deletion UI, so we only enable
93 // it if in testing mode and the test specifically requests it by using this
95 return layoutTestMode()
96 && elem->getAttribute(HTMLNames::classAttr) == "needsDeletionUI";
99 bool EditorClientImpl::smartInsertDeleteEnabled()
101 if (m_webView->client())
102 return m_webView->client()->isSmartInsertDeleteEnabled();
106 bool EditorClientImpl::isSelectTrailingWhitespaceEnabled()
108 if (m_webView->client())
109 return m_webView->client()->isSelectTrailingWhitespaceEnabled();
117 bool EditorClientImpl::shouldSpellcheckByDefault()
119 // Spellcheck should be enabled for all editable areas (such as textareas,
120 // contentEditable regions, and designMode docs), except text inputs.
121 const Frame* frame = m_webView->focusedWebCoreFrame();
124 const Editor* editor = frame->editor();
127 if (editor->isSpellCheckingEnabledInFocusedNode())
129 const Document* document = frame->document();
132 const Node* node = document->focusedNode();
133 // If |node| is null, we default to allowing spellchecking. This is done in
134 // order to mitigate the issue when the user clicks outside the textbox, as a
135 // result of which |node| becomes null, resulting in all the spell check
136 // markers being deleted. Also, the Frame will decide not to do spellchecking
137 // if the user can't edit - so returning true here will not cause any problems
138 // to the Frame's behavior.
141 const RenderObject* renderer = node->renderer();
145 return !renderer->isTextField();
148 bool EditorClientImpl::isContinuousSpellCheckingEnabled()
150 if (m_spellCheckThisFieldStatus == SpellCheckForcedOff)
152 if (m_spellCheckThisFieldStatus == SpellCheckForcedOn)
154 return shouldSpellcheckByDefault();
157 void EditorClientImpl::toggleContinuousSpellChecking()
159 if (isContinuousSpellCheckingEnabled())
160 m_spellCheckThisFieldStatus = SpellCheckForcedOff;
162 m_spellCheckThisFieldStatus = SpellCheckForcedOn;
165 bool EditorClientImpl::isGrammarCheckingEnabled()
170 void EditorClientImpl::toggleGrammarChecking()
175 int EditorClientImpl::spellCheckerDocumentTag()
177 ASSERT_NOT_REACHED();
181 bool EditorClientImpl::isEditable()
186 bool EditorClientImpl::shouldBeginEditing(Range* range)
188 if (m_webView->client())
189 return m_webView->client()->shouldBeginEditing(WebRange(range));
193 bool EditorClientImpl::shouldEndEditing(Range* range)
195 if (m_webView->client())
196 return m_webView->client()->shouldEndEditing(WebRange(range));
200 bool EditorClientImpl::shouldInsertNode(Node* node,
202 EditorInsertAction action)
204 if (m_webView->client()) {
205 return m_webView->client()->shouldInsertNode(WebNode(node),
207 static_cast<WebEditingAction>(action));
212 bool EditorClientImpl::shouldInsertText(const String& text,
214 EditorInsertAction action)
216 if (m_webView->client()) {
217 return m_webView->client()->shouldInsertText(WebString(text),
219 static_cast<WebEditingAction>(action));
225 bool EditorClientImpl::shouldDeleteRange(Range* range)
227 if (m_webView->client())
228 return m_webView->client()->shouldDeleteRange(WebRange(range));
232 bool EditorClientImpl::shouldChangeSelectedRange(Range* fromRange,
237 if (m_webView->client()) {
238 return m_webView->client()->shouldChangeSelectedRange(WebRange(fromRange),
240 static_cast<WebTextAffinity>(affinity),
246 bool EditorClientImpl::shouldApplyStyle(CSSStyleDeclaration* style,
249 if (m_webView->client()) {
250 // FIXME: Pass a reference to the CSSStyleDeclaration somehow.
251 return m_webView->client()->shouldApplyStyle(WebString(),
257 bool EditorClientImpl::shouldMoveRangeAfterDelete(Range* range,
258 Range* rangeToBeReplaced)
263 void EditorClientImpl::didBeginEditing()
265 if (m_webView->client())
266 m_webView->client()->didBeginEditing();
269 void EditorClientImpl::respondToChangedSelection()
271 if (m_webView->client()) {
272 Frame* frame = m_webView->focusedWebCoreFrame();
274 m_webView->client()->didChangeSelection(!frame->selection()->isRange());
278 void EditorClientImpl::respondToChangedContents()
280 if (m_webView->client())
281 m_webView->client()->didChangeContents();
284 void EditorClientImpl::didEndEditing()
286 if (m_webView->client())
287 m_webView->client()->didEndEditing();
290 void EditorClientImpl::didWriteSelectionToPasteboard()
294 void EditorClientImpl::didSetSelectionTypesForPasteboard()
298 void EditorClientImpl::registerCommandForUndo(PassRefPtr<EditCommand> command)
300 if (m_undoStack.size() == maximumUndoStackDepth)
301 m_undoStack.removeFirst(); // drop oldest item off the far end
304 m_undoStack.append(command);
307 void EditorClientImpl::registerCommandForRedo(PassRefPtr<EditCommand> command)
309 m_redoStack.append(command);
312 void EditorClientImpl::clearUndoRedoOperations()
318 bool EditorClientImpl::canUndo() const
320 return !m_undoStack.isEmpty();
323 bool EditorClientImpl::canRedo() const
325 return !m_redoStack.isEmpty();
328 void EditorClientImpl::undo()
331 EditCommandStack::iterator back = --m_undoStack.end();
332 RefPtr<EditCommand> command(*back);
333 m_undoStack.remove(back);
335 // unapply will call us back to push this command onto the redo stack.
339 void EditorClientImpl::redo()
342 EditCommandStack::iterator back = --m_redoStack.end();
343 RefPtr<EditCommand> command(*back);
344 m_redoStack.remove(back);
349 // reapply will call us back to push this command onto the undo stack.
355 // The below code was adapted from the WebKit file webview.cpp
358 static const unsigned CtrlKey = 1 << 0;
359 static const unsigned AltKey = 1 << 1;
360 static const unsigned ShiftKey = 1 << 2;
361 static const unsigned MetaKey = 1 << 3;
363 // Aliases for the generic key defintions to make kbd shortcuts definitions more
365 static const unsigned OptionKey = AltKey;
367 // Do not use this constant for anything but cursor movement commands. Keys
368 // with cmd set have their |isSystemKey| bit set, so chances are the shortcut
369 // will not be executed. Another, less important, reason is that shortcuts
370 // defined in the renderer do not blink the menu item that they triggered. See
371 // http://crbug.com/25856 and the bugs linked from there for details.
372 static const unsigned CommandKey = MetaKey;
375 // Keys with special meaning. These will be delegated to the editor using
376 // the execCommand() method
377 struct KeyDownEntry {
383 struct KeyPressEntry {
389 static const KeyDownEntry keyDownEntries[] = {
390 { VKEY_LEFT, 0, "MoveLeft" },
391 { VKEY_LEFT, ShiftKey, "MoveLeftAndModifySelection" },
393 { VKEY_LEFT, OptionKey, "MoveWordLeft" },
394 { VKEY_LEFT, OptionKey | ShiftKey,
395 "MoveWordLeftAndModifySelection" },
397 { VKEY_LEFT, CtrlKey, "MoveWordLeft" },
398 { VKEY_LEFT, CtrlKey | ShiftKey,
399 "MoveWordLeftAndModifySelection" },
401 { VKEY_RIGHT, 0, "MoveRight" },
402 { VKEY_RIGHT, ShiftKey, "MoveRightAndModifySelection" },
404 { VKEY_RIGHT, OptionKey, "MoveWordRight" },
405 { VKEY_RIGHT, OptionKey | ShiftKey,
406 "MoveWordRightAndModifySelection" },
408 { VKEY_RIGHT, CtrlKey, "MoveWordRight" },
409 { VKEY_RIGHT, CtrlKey | ShiftKey,
410 "MoveWordRightAndModifySelection" },
412 { VKEY_UP, 0, "MoveUp" },
413 { VKEY_UP, ShiftKey, "MoveUpAndModifySelection" },
414 { VKEY_PRIOR, ShiftKey, "MovePageUpAndModifySelection" },
415 { VKEY_DOWN, 0, "MoveDown" },
416 { VKEY_DOWN, ShiftKey, "MoveDownAndModifySelection" },
417 { VKEY_NEXT, ShiftKey, "MovePageDownAndModifySelection" },
419 { VKEY_PRIOR, 0, "MovePageUp" },
420 { VKEY_NEXT, 0, "MovePageDown" },
422 { VKEY_HOME, 0, "MoveToBeginningOfLine" },
423 { VKEY_HOME, ShiftKey,
424 "MoveToBeginningOfLineAndModifySelection" },
426 { VKEY_LEFT, CommandKey, "MoveToBeginningOfLine" },
427 { VKEY_LEFT, CommandKey | ShiftKey,
428 "MoveToBeginningOfLineAndModifySelection" },
429 { VKEY_PRIOR, OptionKey, "MovePageUp" },
430 { VKEY_NEXT, OptionKey, "MovePageDown" },
433 { VKEY_UP, CommandKey, "MoveToBeginningOfDocument" },
434 { VKEY_UP, CommandKey | ShiftKey,
435 "MoveToBeginningOfDocumentAndModifySelection" },
437 { VKEY_HOME, CtrlKey, "MoveToBeginningOfDocument" },
438 { VKEY_HOME, CtrlKey | ShiftKey,
439 "MoveToBeginningOfDocumentAndModifySelection" },
441 { VKEY_END, 0, "MoveToEndOfLine" },
442 { VKEY_END, ShiftKey, "MoveToEndOfLineAndModifySelection" },
444 { VKEY_DOWN, CommandKey, "MoveToEndOfDocument" },
445 { VKEY_DOWN, CommandKey | ShiftKey,
446 "MoveToEndOfDocumentAndModifySelection" },
448 { VKEY_END, CtrlKey, "MoveToEndOfDocument" },
449 { VKEY_END, CtrlKey | ShiftKey,
450 "MoveToEndOfDocumentAndModifySelection" },
453 { VKEY_RIGHT, CommandKey, "MoveToEndOfLine" },
454 { VKEY_RIGHT, CommandKey | ShiftKey,
455 "MoveToEndOfLineAndModifySelection" },
457 { VKEY_BACK, 0, "DeleteBackward" },
458 { VKEY_BACK, ShiftKey, "DeleteBackward" },
459 { VKEY_DELETE, 0, "DeleteForward" },
461 { VKEY_BACK, OptionKey, "DeleteWordBackward" },
462 { VKEY_DELETE, OptionKey, "DeleteWordForward" },
464 { VKEY_BACK, CtrlKey, "DeleteWordBackward" },
465 { VKEY_DELETE, CtrlKey, "DeleteWordForward" },
467 { 'B', CtrlKey, "ToggleBold" },
468 { 'I', CtrlKey, "ToggleItalic" },
469 { 'U', CtrlKey, "ToggleUnderline" },
470 { VKEY_ESCAPE, 0, "Cancel" },
471 { VKEY_OEM_PERIOD, CtrlKey, "Cancel" },
472 { VKEY_TAB, 0, "InsertTab" },
473 { VKEY_TAB, ShiftKey, "InsertBacktab" },
474 { VKEY_RETURN, 0, "InsertNewline" },
475 { VKEY_RETURN, CtrlKey, "InsertNewline" },
476 { VKEY_RETURN, AltKey, "InsertNewline" },
477 { VKEY_RETURN, AltKey | ShiftKey, "InsertNewline" },
478 { VKEY_RETURN, ShiftKey, "InsertLineBreak" },
479 { VKEY_INSERT, CtrlKey, "Copy" },
480 { VKEY_INSERT, ShiftKey, "Paste" },
481 { VKEY_DELETE, ShiftKey, "Cut" },
483 // On OS X, we pipe these back to the browser, so that it can do menu item
485 { 'C', CtrlKey, "Copy" },
486 { 'V', CtrlKey, "Paste" },
487 { 'V', CtrlKey | ShiftKey, "PasteAndMatchStyle" },
488 { 'X', CtrlKey, "Cut" },
489 { 'A', CtrlKey, "SelectAll" },
490 { 'Z', CtrlKey, "Undo" },
491 { 'Z', CtrlKey | ShiftKey, "Redo" },
492 { 'Y', CtrlKey, "Redo" },
496 static const KeyPressEntry keyPressEntries[] = {
497 { '\t', 0, "InsertTab" },
498 { '\t', ShiftKey, "InsertBacktab" },
499 { '\r', 0, "InsertNewline" },
500 { '\r', CtrlKey, "InsertNewline" },
501 { '\r', ShiftKey, "InsertLineBreak" },
502 { '\r', AltKey, "InsertNewline" },
503 { '\r', AltKey | ShiftKey, "InsertNewline" },
506 const char* EditorClientImpl::interpretKeyEvent(const KeyboardEvent* evt)
508 const PlatformKeyboardEvent* keyEvent = evt->keyEvent();
512 static HashMap<int, const char*>* keyDownCommandsMap = 0;
513 static HashMap<int, const char*>* keyPressCommandsMap = 0;
515 if (!keyDownCommandsMap) {
516 keyDownCommandsMap = new HashMap<int, const char*>;
517 keyPressCommandsMap = new HashMap<int, const char*>;
519 for (unsigned i = 0; i < arraysize(keyDownEntries); i++) {
520 keyDownCommandsMap->set(keyDownEntries[i].modifiers << 16 | keyDownEntries[i].virtualKey,
521 keyDownEntries[i].name);
524 for (unsigned i = 0; i < arraysize(keyPressEntries); i++) {
525 keyPressCommandsMap->set(keyPressEntries[i].modifiers << 16 | keyPressEntries[i].charCode,
526 keyPressEntries[i].name);
530 unsigned modifiers = 0;
531 if (keyEvent->shiftKey())
532 modifiers |= ShiftKey;
533 if (keyEvent->altKey())
535 if (keyEvent->ctrlKey())
536 modifiers |= CtrlKey;
537 if (keyEvent->metaKey())
538 modifiers |= MetaKey;
540 if (keyEvent->type() == PlatformKeyboardEvent::RawKeyDown) {
541 int mapKey = modifiers << 16 | evt->keyCode();
542 return mapKey ? keyDownCommandsMap->get(mapKey) : 0;
545 int mapKey = modifiers << 16 | evt->charCode();
546 return mapKey ? keyPressCommandsMap->get(mapKey) : 0;
549 bool EditorClientImpl::handleEditingKeyboardEvent(KeyboardEvent* evt)
551 const PlatformKeyboardEvent* keyEvent = evt->keyEvent();
552 // do not treat this as text input if it's a system key event
553 if (!keyEvent || keyEvent->isSystemKey())
556 Frame* frame = evt->target()->toNode()->document()->frame();
560 String commandName = interpretKeyEvent(evt);
561 Editor::Command command = frame->editor()->command(commandName);
563 if (keyEvent->type() == PlatformKeyboardEvent::RawKeyDown) {
564 // WebKit doesn't have enough information about mode to decide how
565 // commands that just insert text if executed via Editor should be treated,
566 // so we leave it upon WebCore to either handle them immediately
567 // (e.g. Tab that changes focus) or let a keypress event be generated
568 // (e.g. Tab that inserts a Tab character, or Enter).
569 if (command.isTextInsertion() || commandName.isEmpty())
571 if (command.execute(evt)) {
572 if (m_webView->client())
573 m_webView->client()->didExecuteCommand(WebString(commandName));
579 if (command.execute(evt)) {
580 if (m_webView->client())
581 m_webView->client()->didExecuteCommand(WebString(commandName));
585 // Here we need to filter key events.
586 // On Gtk/Linux, it emits key events with ASCII text and ctrl on for ctrl-<x>.
587 // In Webkit, EditorClient::handleKeyboardEvent in
588 // WebKit/gtk/WebCoreSupport/EditorClientGtk.cpp drop such events.
589 // On Mac, it emits key events with ASCII text and meta on for Command-<x>.
590 // These key events should not emit text insert event.
591 // Alt key would be used to insert alternative character, so we should let
592 // through. Also note that Ctrl-Alt combination equals to AltGr key which is
593 // also used to insert alternative character.
594 // http://code.google.com/p/chromium/issues/detail?id=10846
595 // Windows sets both alt and meta are on when "Alt" key pressed.
596 // http://code.google.com/p/chromium/issues/detail?id=2215
597 // Also, we should not rely on an assumption that keyboards don't
598 // send ASCII characters when pressing a control key on Windows,
599 // which may be configured to do it so by user.
600 // See also http://en.wikipedia.org/wiki/Keyboard_Layout
601 // FIXME(ukai): investigate more detail for various keyboard layout.
602 if (evt->keyEvent()->text().length() == 1) {
603 UChar ch = evt->keyEvent()->text()[0U];
605 // Don't insert null or control characters as they can result in
606 // unexpected behaviour
610 // Don't insert ASCII character if ctrl w/o alt or meta is on.
611 // On Mac, we should ignore events when meta is on (Command-<x>).
613 if (evt->keyEvent()->ctrlKey() && !evt->keyEvent()->altKey())
616 if (evt->keyEvent()->metaKey())
623 if (!frame->editor()->canEdit())
626 return frame->editor()->insertText(evt->keyEvent()->text(), evt);
629 void EditorClientImpl::handleKeyboardEvent(KeyboardEvent* evt)
631 if (evt->keyCode() == VKEY_DOWN
632 || evt->keyCode() == VKEY_UP) {
633 ASSERT(evt->target()->toNode());
634 showFormAutofillForNode(evt->target()->toNode());
637 // Give the embedder a chance to handle the keyboard event.
638 if ((m_webView->client()
639 && m_webView->client()->handleCurrentKeyboardEvent())
640 || handleEditingKeyboardEvent(evt))
641 evt->setDefaultHandled();
644 void EditorClientImpl::handleInputMethodKeydown(KeyboardEvent* keyEvent)
646 // We handle IME within chrome.
649 void EditorClientImpl::textFieldDidBeginEditing(Element* element)
651 HTMLInputElement* inputElement = toHTMLInputElement(element);
652 if (m_webView->client() && inputElement)
653 m_webView->client()->textFieldDidBeginEditing(WebInputElement(inputElement));
656 void EditorClientImpl::textFieldDidEndEditing(Element* element)
658 HTMLInputElement* inputElement = toHTMLInputElement(element);
659 if (m_webView->client() && inputElement)
660 m_webView->client()->textFieldDidEndEditing(WebInputElement(inputElement));
662 // Notification that focus was lost. Be careful with this, it's also sent
663 // when the page is being closed.
665 // Cancel any pending DoAutofill call.
666 m_autofillArgs.clear();
667 m_autofillTimer.stop();
669 // Hide any showing popup.
670 m_webView->hideAutoFillPopup();
672 if (!m_webView->client())
673 return; // The page is getting closed, don't fill the password.
675 // Notify any password-listener of the focus change.
679 WebFrameImpl* webframe = WebFrameImpl::fromFrame(inputElement->document()->frame());
683 WebPasswordAutocompleteListener* listener = webframe->getPasswordListener(inputElement);
687 listener->didBlurInputElement(inputElement->value());
690 void EditorClientImpl::textDidChangeInTextField(Element* element)
692 ASSERT(element->hasLocalName(HTMLNames::inputTag));
693 HTMLInputElement* inputElement = static_cast<HTMLInputElement*>(element);
694 if (m_webView->client())
695 m_webView->client()->textFieldDidChange(WebInputElement(inputElement));
697 // Note that we only show the autofill popup in this case if the caret is at
698 // the end. This matches FireFox and Safari but not IE.
699 autofill(inputElement, false, false, true);
702 bool EditorClientImpl::showFormAutofillForNode(Node* node)
704 HTMLInputElement* inputElement = toHTMLInputElement(node);
706 return autofill(inputElement, true, true, false);
710 bool EditorClientImpl::autofill(HTMLInputElement* inputElement,
711 bool autofillFormOnly,
712 bool autofillOnEmptyValue,
713 bool requireCaretAtEnd)
715 // Cancel any pending DoAutofill call.
716 m_autofillArgs.clear();
717 m_autofillTimer.stop();
719 // FIXME: Remove the extraneous isEnabledFormControl call below.
720 // Let's try to trigger autofill for that field, if applicable.
721 if (!inputElement->isEnabledFormControl() || !inputElement->isTextField()
722 || inputElement->isPasswordField() || !inputElement->autoComplete()
723 || !inputElement->isEnabledFormControl()
724 || inputElement->isReadOnlyFormControl())
727 WebString name = WebInputElement(inputElement).nameForAutofill();
728 if (name.isEmpty()) // If the field has no name, then we won't have values.
731 // Don't attempt to autofill with values that are too large.
732 if (inputElement->value().length() > maximumTextSizeForAutofill)
735 m_autofillArgs = new AutofillArgs();
736 m_autofillArgs->inputElement = inputElement;
737 m_autofillArgs->autofillFormOnly = autofillFormOnly;
738 m_autofillArgs->autofillOnEmptyValue = autofillOnEmptyValue;
739 m_autofillArgs->requireCaretAtEnd = requireCaretAtEnd;
740 m_autofillArgs->backspaceOrDeletePressed = m_backspaceOrDeletePressed;
742 if (!requireCaretAtEnd)
745 // We post a task for doing the autofill as the caret position is not set
746 // properly at this point (http://bugs.webkit.org/show_bug.cgi?id=16976)
747 // and we need it to determine whether or not to trigger autofill.
748 m_autofillTimer.startOneShot(0.0);
753 void EditorClientImpl::doAutofill(Timer<EditorClientImpl>* timer)
755 OwnPtr<AutofillArgs> args(m_autofillArgs.release());
756 HTMLInputElement* inputElement = args->inputElement.get();
758 const String& value = inputElement->value();
760 // Enforce autofill_on_empty_value and caret_at_end.
762 bool isCaretAtEnd = true;
763 if (args->requireCaretAtEnd)
764 isCaretAtEnd = inputElement->selectionStart() == inputElement->selectionEnd()
765 && inputElement->selectionEnd() == static_cast<int>(value.length());
767 if ((!args->autofillOnEmptyValue && value.isEmpty()) || !isCaretAtEnd) {
768 m_webView->hideAutoFillPopup();
772 // First let's see if there is a password listener for that element.
773 // We won't trigger form autofill in that case, as having both behavior on
774 // a node would be confusing.
775 WebFrameImpl* webframe = WebFrameImpl::fromFrame(inputElement->document()->frame());
778 WebPasswordAutocompleteListener* listener = webframe->getPasswordListener(inputElement);
780 if (args->autofillFormOnly)
783 listener->performInlineAutocomplete(value,
784 args->backspaceOrDeletePressed,
789 // Then trigger form autofill.
790 WebString name = WebInputElement(inputElement).nameForAutofill();
791 ASSERT(static_cast<int>(name.length()) > 0);
793 if (m_webView->client())
794 m_webView->client()->queryAutofillSuggestions(WebNode(inputElement),
795 name, WebString(value));
798 void EditorClientImpl::cancelPendingAutofill()
800 m_autofillArgs.clear();
801 m_autofillTimer.stop();
804 void EditorClientImpl::onAutocompleteSuggestionAccepted(HTMLInputElement* textField)
806 if (m_webView->client())
807 m_webView->client()->didAcceptAutocompleteSuggestion(WebInputElement(textField));
809 WebFrameImpl* webframe = WebFrameImpl::fromFrame(textField->document()->frame());
813 webframe->notifiyPasswordListenerOfAutocomplete(WebInputElement(textField));
816 bool EditorClientImpl::doTextFieldCommandFromEvent(Element* element,
817 KeyboardEvent* event)
819 HTMLInputElement* inputElement = toHTMLInputElement(element);
820 if (m_webView->client() && inputElement) {
821 m_webView->client()->textFieldDidReceiveKeyDown(WebInputElement(inputElement),
822 WebKeyboardEventBuilder(*event));
825 // Remember if backspace was pressed for the autofill. It is not clear how to
826 // find if backspace was pressed from textFieldDidBeginEditing and
827 // textDidChangeInTextField as when these methods are called the value of the
828 // input element already contains the type character.
829 m_backspaceOrDeletePressed = event->keyCode() == VKEY_BACK || event->keyCode() == VKEY_DELETE;
831 // The Mac code appears to use this method as a hook to implement special
832 // keyboard commands specific to Safari's auto-fill implementation. We
833 // just return false to allow the default action.
837 void EditorClientImpl::textWillBeDeletedInTextField(Element*)
841 void EditorClientImpl::textDidChangeInTextArea(Element*)
845 void EditorClientImpl::ignoreWordInSpellDocument(const String&)
850 void EditorClientImpl::learnWord(const String&)
855 void EditorClientImpl::checkSpellingOfString(const UChar* text, int length,
856 int* misspellingLocation,
857 int* misspellingLength)
859 // SpellCheckWord will write (0, 0) into the output vars, which is what our
860 // caller expects if the word is spelled correctly.
861 int spellLocation = -1;
864 // Check to see if the provided text is spelled correctly.
865 if (isContinuousSpellCheckingEnabled() && m_webView->client())
866 m_webView->client()->spellCheck(WebString(text, length), spellLocation, spellLength);
872 // Note: the Mac code checks if the pointers are null before writing to them,
874 if (misspellingLocation)
875 *misspellingLocation = spellLocation;
876 if (misspellingLength)
877 *misspellingLength = spellLength;
880 String EditorClientImpl::getAutoCorrectSuggestionForMisspelledWord(const String& misspelledWord)
882 if (!(isContinuousSpellCheckingEnabled() && m_webView->client()))
885 // Do not autocorrect words with capital letters in it except the
886 // first letter. This will remove cases changing "IMB" to "IBM".
887 for (size_t i = 1; i < misspelledWord.length(); i++) {
888 if (u_isupper(static_cast<UChar32>(misspelledWord[i])))
892 return m_webView->client()->autoCorrectWord(WebString(misspelledWord));
895 void EditorClientImpl::checkGrammarOfString(const UChar*, int length,
896 WTF::Vector<GrammarDetail>&,
897 int* badGrammarLocation,
898 int* badGrammarLength)
901 if (badGrammarLocation)
902 *badGrammarLocation = 0;
903 if (badGrammarLength)
904 *badGrammarLength = 0;
907 void EditorClientImpl::updateSpellingUIWithGrammarString(const String&,
908 const GrammarDetail& detail)
913 void EditorClientImpl::updateSpellingUIWithMisspelledWord(const String& misspelledWord)
915 if (m_webView->client())
916 m_webView->client()->updateSpellingUIWithMisspelledWord(WebString(misspelledWord));
919 void EditorClientImpl::showSpellingUI(bool show)
921 if (m_webView->client())
922 m_webView->client()->showSpellingUI(show);
925 bool EditorClientImpl::spellingUIIsShowing()
927 if (m_webView->client())
928 return m_webView->client()->isShowingSpellingUI();
932 void EditorClientImpl::getGuessesForWord(const String&,
933 WTF::Vector<String>& guesses)
938 void EditorClientImpl::willSetInputMethodState()
940 if (m_webView->client())
941 m_webView->client()->resetInputMethod();
944 void EditorClientImpl::setInputMethodState(bool)