EditorClientImpl.cpp revision ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddb
1/*
2 * Copyright (C) 2006, 2007 Apple, Inc.  All rights reserved.
3 * Copyright (C) 2010 Google, Inc.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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.
13 *
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.
25 */
26
27#include "config.h"
28#include "EditorClientImpl.h"
29
30#include "Document.h"
31#include "EditCommand.h"
32#include "Editor.h"
33#include "EventHandler.h"
34#include "EventNames.h"
35#include "Frame.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"
43
44#include "DOMUtilitiesPrivate.h"
45#include "WebAutoFillClient.h"
46#include "WebEditingAction.h"
47#include "WebElement.h"
48#include "WebFrameClient.h"
49#include "WebFrameImpl.h"
50#include "WebKit.h"
51#include "WebInputElement.h"
52#include "WebInputEventConversion.h"
53#include "WebNode.h"
54#include "WebPasswordAutocompleteListener.h"
55#include "WebRange.h"
56#include "WebTextAffinity.h"
57#include "WebViewClient.h"
58#include "WebViewImpl.h"
59
60using namespace WebCore;
61
62namespace WebKit {
63
64// Arbitrary depth limit for the undo stack, to keep it from using
65// unbounded memory.  This is the maximum number of distinct undoable
66// actions -- unbroken stretches of typed characters are coalesced
67// into a single action.
68static const size_t maximumUndoStackDepth = 1000;
69
70// The size above which we stop triggering autofill for an input text field
71// (so to avoid sending long strings through IPC).
72static const size_t maximumTextSizeForAutofill = 1000;
73
74EditorClientImpl::EditorClientImpl(WebViewImpl* webview)
75    : m_webView(webview)
76    , m_inRedo(false)
77    , m_backspaceOrDeletePressed(false)
78    , m_spellCheckThisFieldStatus(SpellCheckAutomatic)
79    , m_autofillTimer(this, &EditorClientImpl::doAutofill)
80{
81}
82
83EditorClientImpl::~EditorClientImpl()
84{
85}
86
87void EditorClientImpl::pageDestroyed()
88{
89    // Our lifetime is bound to the WebViewImpl.
90}
91
92bool EditorClientImpl::shouldShowDeleteInterface(HTMLElement* elem)
93{
94    // Normally, we don't care to show WebCore's deletion UI, so we only enable
95    // it if in testing mode and the test specifically requests it by using this
96    // magic class name.
97    return layoutTestMode()
98           && elem->getAttribute(HTMLNames::classAttr) == "needsDeletionUI";
99}
100
101bool EditorClientImpl::smartInsertDeleteEnabled()
102{
103    if (m_webView->client())
104        return m_webView->client()->isSmartInsertDeleteEnabled();
105    return true;
106}
107
108bool EditorClientImpl::isSelectTrailingWhitespaceEnabled()
109{
110    if (m_webView->client())
111        return m_webView->client()->isSelectTrailingWhitespaceEnabled();
112#if OS(WINDOWS)
113    return true;
114#else
115    return false;
116#endif
117}
118
119bool EditorClientImpl::shouldSpellcheckByDefault()
120{
121    // Spellcheck should be enabled for all editable areas (such as textareas,
122    // contentEditable regions, and designMode docs), except text inputs.
123    const Frame* frame = m_webView->focusedWebCoreFrame();
124    if (!frame)
125        return false;
126    const Editor* editor = frame->editor();
127    if (!editor)
128        return false;
129    if (editor->isSpellCheckingEnabledInFocusedNode())
130        return true;
131    const Document* document = frame->document();
132    if (!document)
133        return false;
134    const Node* node = document->focusedNode();
135    // If |node| is null, we default to allowing spellchecking. This is done in
136    // order to mitigate the issue when the user clicks outside the textbox, as a
137    // result of which |node| becomes null, resulting in all the spell check
138    // markers being deleted. Also, the Frame will decide not to do spellchecking
139    // if the user can't edit - so returning true here will not cause any problems
140    // to the Frame's behavior.
141    if (!node)
142        return true;
143    const RenderObject* renderer = node->renderer();
144    if (!renderer)
145        return false;
146
147    return !renderer->isTextField();
148}
149
150bool EditorClientImpl::isContinuousSpellCheckingEnabled()
151{
152    if (m_spellCheckThisFieldStatus == SpellCheckForcedOff)
153        return false;
154    if (m_spellCheckThisFieldStatus == SpellCheckForcedOn)
155        return true;
156    return shouldSpellcheckByDefault();
157}
158
159void EditorClientImpl::toggleContinuousSpellChecking()
160{
161    if (isContinuousSpellCheckingEnabled())
162        m_spellCheckThisFieldStatus = SpellCheckForcedOff;
163    else
164        m_spellCheckThisFieldStatus = SpellCheckForcedOn;
165
166    WebFrameImpl* webframe = WebFrameImpl::fromFrame(
167        m_webView->focusedWebCoreFrame());
168    if (webframe)
169        webframe->client()->didToggleContinuousSpellChecking(webframe);
170}
171
172bool EditorClientImpl::isGrammarCheckingEnabled()
173{
174    return false;
175}
176
177void EditorClientImpl::toggleGrammarChecking()
178{
179    notImplemented();
180}
181
182int EditorClientImpl::spellCheckerDocumentTag()
183{
184    ASSERT_NOT_REACHED();
185    return 0;
186}
187
188bool EditorClientImpl::isEditable()
189{
190    return false;
191}
192
193bool EditorClientImpl::shouldBeginEditing(Range* range)
194{
195    if (m_webView->client())
196        return m_webView->client()->shouldBeginEditing(WebRange(range));
197    return true;
198}
199
200bool EditorClientImpl::shouldEndEditing(Range* range)
201{
202    if (m_webView->client())
203        return m_webView->client()->shouldEndEditing(WebRange(range));
204    return true;
205}
206
207bool EditorClientImpl::shouldInsertNode(Node* node,
208                                        Range* range,
209                                        EditorInsertAction action)
210{
211    if (m_webView->client()) {
212        return m_webView->client()->shouldInsertNode(WebNode(node),
213                                                     WebRange(range),
214                                                     static_cast<WebEditingAction>(action));
215    }
216    return true;
217}
218
219bool EditorClientImpl::shouldInsertText(const String& text,
220                                        Range* range,
221                                        EditorInsertAction action)
222{
223    if (m_webView->client()) {
224        return m_webView->client()->shouldInsertText(WebString(text),
225                                                     WebRange(range),
226                                                     static_cast<WebEditingAction>(action));
227    }
228    return true;
229}
230
231
232bool EditorClientImpl::shouldDeleteRange(Range* range)
233{
234    if (m_webView->client())
235        return m_webView->client()->shouldDeleteRange(WebRange(range));
236    return true;
237}
238
239bool EditorClientImpl::shouldChangeSelectedRange(Range* fromRange,
240                                                 Range* toRange,
241                                                 EAffinity affinity,
242                                                 bool stillSelecting)
243{
244    if (m_webView->client()) {
245        return m_webView->client()->shouldChangeSelectedRange(WebRange(fromRange),
246                                                              WebRange(toRange),
247                                                              static_cast<WebTextAffinity>(affinity),
248                                                              stillSelecting);
249    }
250    return true;
251}
252
253bool EditorClientImpl::shouldApplyStyle(CSSStyleDeclaration* style,
254                                        Range* range)
255{
256    if (m_webView->client()) {
257        // FIXME: Pass a reference to the CSSStyleDeclaration somehow.
258        return m_webView->client()->shouldApplyStyle(WebString(),
259                                                     WebRange(range));
260    }
261    return true;
262}
263
264bool EditorClientImpl::shouldMoveRangeAfterDelete(Range* range,
265                                                  Range* rangeToBeReplaced)
266{
267    return true;
268}
269
270void EditorClientImpl::didBeginEditing()
271{
272    if (m_webView->client())
273        m_webView->client()->didBeginEditing();
274}
275
276void EditorClientImpl::respondToChangedSelection()
277{
278    if (m_webView->client()) {
279        Frame* frame = m_webView->focusedWebCoreFrame();
280        if (frame)
281            m_webView->client()->didChangeSelection(!frame->selection()->isRange());
282    }
283}
284
285void EditorClientImpl::respondToChangedContents()
286{
287    if (m_webView->client())
288        m_webView->client()->didChangeContents();
289}
290
291void EditorClientImpl::didEndEditing()
292{
293    if (m_webView->client())
294        m_webView->client()->didEndEditing();
295}
296
297void EditorClientImpl::didWriteSelectionToPasteboard()
298{
299}
300
301void EditorClientImpl::didSetSelectionTypesForPasteboard()
302{
303}
304
305void EditorClientImpl::registerCommandForUndo(PassRefPtr<EditCommand> command)
306{
307    if (m_undoStack.size() == maximumUndoStackDepth)
308        m_undoStack.removeFirst(); // drop oldest item off the far end
309    if (!m_inRedo)
310        m_redoStack.clear();
311    m_undoStack.append(command);
312}
313
314void EditorClientImpl::registerCommandForRedo(PassRefPtr<EditCommand> command)
315{
316    m_redoStack.append(command);
317}
318
319void EditorClientImpl::clearUndoRedoOperations()
320{
321    m_undoStack.clear();
322    m_redoStack.clear();
323}
324
325bool EditorClientImpl::canUndo() const
326{
327    return !m_undoStack.isEmpty();
328}
329
330bool EditorClientImpl::canRedo() const
331{
332    return !m_redoStack.isEmpty();
333}
334
335void EditorClientImpl::undo()
336{
337    if (canUndo()) {
338        EditCommandStack::iterator back = --m_undoStack.end();
339        RefPtr<EditCommand> command(*back);
340        m_undoStack.remove(back);
341        command->unapply();
342        // unapply will call us back to push this command onto the redo stack.
343    }
344}
345
346void EditorClientImpl::redo()
347{
348    if (canRedo()) {
349        EditCommandStack::iterator back = --m_redoStack.end();
350        RefPtr<EditCommand> command(*back);
351        m_redoStack.remove(back);
352
353        ASSERT(!m_inRedo);
354        m_inRedo = true;
355        command->reapply();
356        // reapply will call us back to push this command onto the undo stack.
357        m_inRedo = false;
358    }
359}
360
361//
362// The below code was adapted from the WebKit file webview.cpp
363//
364
365static const unsigned CtrlKey = 1 << 0;
366static const unsigned AltKey = 1 << 1;
367static const unsigned ShiftKey = 1 << 2;
368static const unsigned MetaKey = 1 << 3;
369#if OS(DARWIN)
370// Aliases for the generic key defintions to make kbd shortcuts definitions more
371// readable on OS X.
372static const unsigned OptionKey  = AltKey;
373
374// Do not use this constant for anything but cursor movement commands. Keys
375// with cmd set have their |isSystemKey| bit set, so chances are the shortcut
376// will not be executed. Another, less important, reason is that shortcuts
377// defined in the renderer do not blink the menu item that they triggered.  See
378// http://crbug.com/25856 and the bugs linked from there for details.
379static const unsigned CommandKey = MetaKey;
380#endif
381
382// Keys with special meaning. These will be delegated to the editor using
383// the execCommand() method
384struct KeyDownEntry {
385    unsigned virtualKey;
386    unsigned modifiers;
387    const char* name;
388};
389
390struct KeyPressEntry {
391    unsigned charCode;
392    unsigned modifiers;
393    const char* name;
394};
395
396static const KeyDownEntry keyDownEntries[] = {
397    { VKEY_LEFT,   0,                  "MoveLeft"                             },
398    { VKEY_LEFT,   ShiftKey,           "MoveLeftAndModifySelection"           },
399#if OS(DARWIN)
400    { VKEY_LEFT,   OptionKey,          "MoveWordLeft"                         },
401    { VKEY_LEFT,   OptionKey | ShiftKey,
402        "MoveWordLeftAndModifySelection"                                      },
403#else
404    { VKEY_LEFT,   CtrlKey,            "MoveWordLeft"                         },
405    { VKEY_LEFT,   CtrlKey | ShiftKey,
406        "MoveWordLeftAndModifySelection"                                      },
407#endif
408    { VKEY_RIGHT,  0,                  "MoveRight"                            },
409    { VKEY_RIGHT,  ShiftKey,           "MoveRightAndModifySelection"          },
410#if OS(DARWIN)
411    { VKEY_RIGHT,  OptionKey,          "MoveWordRight"                        },
412    { VKEY_RIGHT,  OptionKey | ShiftKey,
413      "MoveWordRightAndModifySelection"                                       },
414#else
415    { VKEY_RIGHT,  CtrlKey,            "MoveWordRight"                        },
416    { VKEY_RIGHT,  CtrlKey | ShiftKey,
417      "MoveWordRightAndModifySelection"                                       },
418#endif
419    { VKEY_UP,     0,                  "MoveUp"                               },
420    { VKEY_UP,     ShiftKey,           "MoveUpAndModifySelection"             },
421    { VKEY_PRIOR,  ShiftKey,           "MovePageUpAndModifySelection"         },
422    { VKEY_DOWN,   0,                  "MoveDown"                             },
423    { VKEY_DOWN,   ShiftKey,           "MoveDownAndModifySelection"           },
424    { VKEY_NEXT,   ShiftKey,           "MovePageDownAndModifySelection"       },
425#if !OS(DARWIN)
426    { VKEY_PRIOR,  0,                  "MovePageUp"                           },
427    { VKEY_NEXT,   0,                  "MovePageDown"                         },
428#endif
429    { VKEY_HOME,   0,                  "MoveToBeginningOfLine"                },
430    { VKEY_HOME,   ShiftKey,
431        "MoveToBeginningOfLineAndModifySelection"                             },
432#if OS(DARWIN)
433    { VKEY_LEFT,   CommandKey,         "MoveToBeginningOfLine"                },
434    { VKEY_LEFT,   CommandKey | ShiftKey,
435      "MoveToBeginningOfLineAndModifySelection"                               },
436    { VKEY_PRIOR,  OptionKey,          "MovePageUp"                           },
437    { VKEY_NEXT,   OptionKey,          "MovePageDown"                         },
438#endif
439#if OS(DARWIN)
440    { VKEY_UP,     CommandKey,         "MoveToBeginningOfDocument"            },
441    { VKEY_UP,     CommandKey | ShiftKey,
442        "MoveToBeginningOfDocumentAndModifySelection"                         },
443#else
444    { VKEY_HOME,   CtrlKey,            "MoveToBeginningOfDocument"            },
445    { VKEY_HOME,   CtrlKey | ShiftKey,
446        "MoveToBeginningOfDocumentAndModifySelection"                         },
447#endif
448    { VKEY_END,    0,                  "MoveToEndOfLine"                      },
449    { VKEY_END,    ShiftKey,           "MoveToEndOfLineAndModifySelection"    },
450#if OS(DARWIN)
451    { VKEY_DOWN,   CommandKey,         "MoveToEndOfDocument"                  },
452    { VKEY_DOWN,   CommandKey | ShiftKey,
453        "MoveToEndOfDocumentAndModifySelection"                               },
454#else
455    { VKEY_END,    CtrlKey,            "MoveToEndOfDocument"                  },
456    { VKEY_END,    CtrlKey | ShiftKey,
457        "MoveToEndOfDocumentAndModifySelection"                               },
458#endif
459#if OS(DARWIN)
460    { VKEY_RIGHT,  CommandKey,         "MoveToEndOfLine"                      },
461    { VKEY_RIGHT,  CommandKey | ShiftKey,
462        "MoveToEndOfLineAndModifySelection"                                   },
463#endif
464    { VKEY_BACK,   0,                  "DeleteBackward"                       },
465    { VKEY_BACK,   ShiftKey,           "DeleteBackward"                       },
466    { VKEY_DELETE, 0,                  "DeleteForward"                        },
467#if OS(DARWIN)
468    { VKEY_BACK,   OptionKey,          "DeleteWordBackward"                   },
469    { VKEY_DELETE, OptionKey,          "DeleteWordForward"                    },
470#else
471    { VKEY_BACK,   CtrlKey,            "DeleteWordBackward"                   },
472    { VKEY_DELETE, CtrlKey,            "DeleteWordForward"                    },
473#endif
474    { 'B',         CtrlKey,            "ToggleBold"                           },
475    { 'I',         CtrlKey,            "ToggleItalic"                         },
476    { 'U',         CtrlKey,            "ToggleUnderline"                      },
477    { VKEY_ESCAPE, 0,                  "Cancel"                               },
478    { VKEY_OEM_PERIOD, CtrlKey,        "Cancel"                               },
479    { VKEY_TAB,    0,                  "InsertTab"                            },
480    { VKEY_TAB,    ShiftKey,           "InsertBacktab"                        },
481    { VKEY_RETURN, 0,                  "InsertNewline"                        },
482    { VKEY_RETURN, CtrlKey,            "InsertNewline"                        },
483    { VKEY_RETURN, AltKey,             "InsertNewline"                        },
484    { VKEY_RETURN, AltKey | ShiftKey,  "InsertNewline"                        },
485    { VKEY_RETURN, ShiftKey,           "InsertLineBreak"                      },
486    { VKEY_INSERT, CtrlKey,            "Copy"                                 },
487    { VKEY_INSERT, ShiftKey,           "Paste"                                },
488    { VKEY_DELETE, ShiftKey,           "Cut"                                  },
489#if !OS(DARWIN)
490    // On OS X, we pipe these back to the browser, so that it can do menu item
491    // blinking.
492    { 'C',         CtrlKey,            "Copy"                                 },
493    { 'V',         CtrlKey,            "Paste"                                },
494    { 'V',         CtrlKey | ShiftKey, "PasteAndMatchStyle"                   },
495    { 'X',         CtrlKey,            "Cut"                                  },
496    { 'A',         CtrlKey,            "SelectAll"                            },
497    { 'Z',         CtrlKey,            "Undo"                                 },
498    { 'Z',         CtrlKey | ShiftKey, "Redo"                                 },
499    { 'Y',         CtrlKey,            "Redo"                                 },
500#endif
501};
502
503static const KeyPressEntry keyPressEntries[] = {
504    { '\t',   0,                  "InsertTab"                                 },
505    { '\t',   ShiftKey,           "InsertBacktab"                             },
506    { '\r',   0,                  "InsertNewline"                             },
507    { '\r',   CtrlKey,            "InsertNewline"                             },
508    { '\r',   ShiftKey,           "InsertLineBreak"                           },
509    { '\r',   AltKey,             "InsertNewline"                             },
510    { '\r',   AltKey | ShiftKey,  "InsertNewline"                             },
511};
512
513const char* EditorClientImpl::interpretKeyEvent(const KeyboardEvent* evt)
514{
515    const PlatformKeyboardEvent* keyEvent = evt->keyEvent();
516    if (!keyEvent)
517        return "";
518
519    static HashMap<int, const char*>* keyDownCommandsMap = 0;
520    static HashMap<int, const char*>* keyPressCommandsMap = 0;
521
522    if (!keyDownCommandsMap) {
523        keyDownCommandsMap = new HashMap<int, const char*>;
524        keyPressCommandsMap = new HashMap<int, const char*>;
525
526        for (unsigned i = 0; i < arraysize(keyDownEntries); i++) {
527            keyDownCommandsMap->set(keyDownEntries[i].modifiers << 16 | keyDownEntries[i].virtualKey,
528                                    keyDownEntries[i].name);
529        }
530
531        for (unsigned i = 0; i < arraysize(keyPressEntries); i++) {
532            keyPressCommandsMap->set(keyPressEntries[i].modifiers << 16 | keyPressEntries[i].charCode,
533                                     keyPressEntries[i].name);
534        }
535    }
536
537    unsigned modifiers = 0;
538    if (keyEvent->shiftKey())
539        modifiers |= ShiftKey;
540    if (keyEvent->altKey())
541        modifiers |= AltKey;
542    if (keyEvent->ctrlKey())
543        modifiers |= CtrlKey;
544    if (keyEvent->metaKey())
545        modifiers |= MetaKey;
546
547    if (keyEvent->type() == PlatformKeyboardEvent::RawKeyDown) {
548        int mapKey = modifiers << 16 | evt->keyCode();
549        return mapKey ? keyDownCommandsMap->get(mapKey) : 0;
550    }
551
552    int mapKey = modifiers << 16 | evt->charCode();
553    return mapKey ? keyPressCommandsMap->get(mapKey) : 0;
554}
555
556bool EditorClientImpl::handleEditingKeyboardEvent(KeyboardEvent* evt)
557{
558    const PlatformKeyboardEvent* keyEvent = evt->keyEvent();
559    // do not treat this as text input if it's a system key event
560    if (!keyEvent || keyEvent->isSystemKey())
561        return false;
562
563    Frame* frame = evt->target()->toNode()->document()->frame();
564    if (!frame)
565        return false;
566
567    String commandName = interpretKeyEvent(evt);
568    Editor::Command command = frame->editor()->command(commandName);
569
570    if (keyEvent->type() == PlatformKeyboardEvent::RawKeyDown) {
571        // WebKit doesn't have enough information about mode to decide how
572        // commands that just insert text if executed via Editor should be treated,
573        // so we leave it upon WebCore to either handle them immediately
574        // (e.g. Tab that changes focus) or let a keypress event be generated
575        // (e.g. Tab that inserts a Tab character, or Enter).
576        if (command.isTextInsertion() || commandName.isEmpty())
577            return false;
578        if (command.execute(evt)) {
579            if (m_webView->client())
580                m_webView->client()->didExecuteCommand(WebString(commandName));
581            return true;
582        }
583        return false;
584    }
585
586    if (command.execute(evt)) {
587        if (m_webView->client())
588            m_webView->client()->didExecuteCommand(WebString(commandName));
589        return true;
590    }
591
592    // Here we need to filter key events.
593    // On Gtk/Linux, it emits key events with ASCII text and ctrl on for ctrl-<x>.
594    // In Webkit, EditorClient::handleKeyboardEvent in
595    // WebKit/gtk/WebCoreSupport/EditorClientGtk.cpp drop such events.
596    // On Mac, it emits key events with ASCII text and meta on for Command-<x>.
597    // These key events should not emit text insert event.
598    // Alt key would be used to insert alternative character, so we should let
599    // through. Also note that Ctrl-Alt combination equals to AltGr key which is
600    // also used to insert alternative character.
601    // http://code.google.com/p/chromium/issues/detail?id=10846
602    // Windows sets both alt and meta are on when "Alt" key pressed.
603    // http://code.google.com/p/chromium/issues/detail?id=2215
604    // Also, we should not rely on an assumption that keyboards don't
605    // send ASCII characters when pressing a control key on Windows,
606    // which may be configured to do it so by user.
607    // See also http://en.wikipedia.org/wiki/Keyboard_Layout
608    // FIXME(ukai): investigate more detail for various keyboard layout.
609    if (evt->keyEvent()->text().length() == 1) {
610        UChar ch = evt->keyEvent()->text()[0U];
611
612        // Don't insert null or control characters as they can result in
613        // unexpected behaviour
614        if (ch < ' ')
615            return false;
616#if !OS(WINDOWS)
617        // Don't insert ASCII character if ctrl w/o alt or meta is on.
618        // On Mac, we should ignore events when meta is on (Command-<x>).
619        if (ch < 0x80) {
620            if (evt->keyEvent()->ctrlKey() && !evt->keyEvent()->altKey())
621                return false;
622#if OS(DARWIN)
623            if (evt->keyEvent()->metaKey())
624            return false;
625#endif
626        }
627#endif
628    }
629
630    if (!frame->editor()->canEdit())
631        return false;
632
633    return frame->editor()->insertText(evt->keyEvent()->text(), evt);
634}
635
636void EditorClientImpl::handleKeyboardEvent(KeyboardEvent* evt)
637{
638    if (evt->keyCode() == VKEY_DOWN
639        || evt->keyCode() == VKEY_UP) {
640        ASSERT(evt->target()->toNode());
641        showFormAutofillForNode(evt->target()->toNode());
642    }
643
644    // Give the embedder a chance to handle the keyboard event.
645    if ((m_webView->client()
646         && m_webView->client()->handleCurrentKeyboardEvent())
647        || handleEditingKeyboardEvent(evt))
648        evt->setDefaultHandled();
649}
650
651void EditorClientImpl::handleInputMethodKeydown(KeyboardEvent* keyEvent)
652{
653    // We handle IME within chrome.
654}
655
656void EditorClientImpl::textFieldDidBeginEditing(Element* element)
657{
658    HTMLInputElement* inputElement = toHTMLInputElement(element);
659    if (m_webView->autoFillClient() && inputElement)
660        m_webView->autoFillClient()->textFieldDidBeginEditing(WebInputElement(inputElement));
661}
662
663void EditorClientImpl::textFieldDidEndEditing(Element* element)
664{
665    HTMLInputElement* inputElement = toHTMLInputElement(element);
666    if (m_webView->autoFillClient() && inputElement)
667        m_webView->autoFillClient()->textFieldDidEndEditing(WebInputElement(inputElement));
668
669    // Notification that focus was lost.  Be careful with this, it's also sent
670    // when the page is being closed.
671
672    // Cancel any pending DoAutofill call.
673    m_autofillArgs.clear();
674    m_autofillTimer.stop();
675
676    // Hide any showing popup.
677    m_webView->hideAutoFillPopup();
678
679    if (!m_webView->client())
680        return; // The page is getting closed, don't fill the password.
681
682    // Notify any password-listener of the focus change.
683    if (!inputElement)
684        return;
685
686    WebFrameImpl* webframe = WebFrameImpl::fromFrame(inputElement->document()->frame());
687    if (!webframe)
688        return;
689
690    WebPasswordAutocompleteListener* listener = webframe->getPasswordListener(inputElement);
691    if (!listener)
692        return;
693
694    listener->didBlurInputElement(inputElement->value());
695}
696
697void EditorClientImpl::textDidChangeInTextField(Element* element)
698{
699    ASSERT(element->hasLocalName(HTMLNames::inputTag));
700    HTMLInputElement* inputElement = static_cast<HTMLInputElement*>(element);
701    if (m_webView->autoFillClient())
702        m_webView->autoFillClient()->textFieldDidChange(WebInputElement(inputElement));
703
704    // Note that we only show the autofill popup in this case if the caret is at
705    // the end.  This matches FireFox and Safari but not IE.
706    autofill(inputElement, false, false, true);
707}
708
709bool EditorClientImpl::showFormAutofillForNode(Node* node)
710{
711    HTMLInputElement* inputElement = toHTMLInputElement(node);
712    if (inputElement)
713        return autofill(inputElement, true, true, false);
714    return false;
715}
716
717bool EditorClientImpl::autofill(HTMLInputElement* inputElement,
718                                bool autofillFormOnly,
719                                bool autofillOnEmptyValue,
720                                bool requireCaretAtEnd)
721{
722    // Cancel any pending DoAutofill call.
723    m_autofillArgs.clear();
724    m_autofillTimer.stop();
725
726    // FIXME: Remove the extraneous isEnabledFormControl call below.
727    // Let's try to trigger autofill for that field, if applicable.
728    if (!inputElement->isEnabledFormControl() || !inputElement->isTextField()
729        || inputElement->isPasswordField() || !inputElement->autoComplete()
730        || !inputElement->isEnabledFormControl()
731        || inputElement->isReadOnlyFormControl())
732        return false;
733
734    WebString name = WebInputElement(inputElement).nameForAutofill();
735    if (name.isEmpty()) // If the field has no name, then we won't have values.
736        return false;
737
738    // Don't attempt to autofill with values that are too large.
739    if (inputElement->value().length() > maximumTextSizeForAutofill)
740        return false;
741
742    m_autofillArgs = new AutofillArgs();
743    m_autofillArgs->inputElement = inputElement;
744    m_autofillArgs->autofillFormOnly = autofillFormOnly;
745    m_autofillArgs->autofillOnEmptyValue = autofillOnEmptyValue;
746    m_autofillArgs->requireCaretAtEnd = requireCaretAtEnd;
747    m_autofillArgs->backspaceOrDeletePressed = m_backspaceOrDeletePressed;
748
749    if (!requireCaretAtEnd)
750        doAutofill(0);
751    else {
752        // We post a task for doing the autofill as the caret position is not set
753        // properly at this point (http://bugs.webkit.org/show_bug.cgi?id=16976)
754        // and we need it to determine whether or not to trigger autofill.
755        m_autofillTimer.startOneShot(0.0);
756    }
757    return true;
758}
759
760void EditorClientImpl::doAutofill(Timer<EditorClientImpl>* timer)
761{
762    OwnPtr<AutofillArgs> args(m_autofillArgs.release());
763    HTMLInputElement* inputElement = args->inputElement.get();
764
765    const String& value = inputElement->value();
766
767    // Enforce autofill_on_empty_value and caret_at_end.
768
769    bool isCaretAtEnd = true;
770    if (args->requireCaretAtEnd)
771        isCaretAtEnd = inputElement->selectionStart() == inputElement->selectionEnd()
772                       && inputElement->selectionEnd() == static_cast<int>(value.length());
773
774    if ((!args->autofillOnEmptyValue && value.isEmpty()) || !isCaretAtEnd) {
775        m_webView->hideAutoFillPopup();
776        return;
777    }
778
779    // First let's see if there is a password listener for that element.
780    // We won't trigger form autofill in that case, as having both behavior on
781    // a node would be confusing.
782    WebFrameImpl* webframe = WebFrameImpl::fromFrame(inputElement->document()->frame());
783    if (!webframe)
784        return;
785    WebPasswordAutocompleteListener* listener = webframe->getPasswordListener(inputElement);
786    if (listener) {
787        if (args->autofillFormOnly)
788            return;
789
790        listener->performInlineAutocomplete(value,
791                                            args->backspaceOrDeletePressed,
792                                            true);
793        return;
794    }
795}
796
797void EditorClientImpl::cancelPendingAutofill()
798{
799    m_autofillArgs.clear();
800    m_autofillTimer.stop();
801}
802
803void EditorClientImpl::onAutocompleteSuggestionAccepted(HTMLInputElement* textField)
804{
805    if (m_webView->autoFillClient())
806        m_webView->autoFillClient()->didAcceptAutocompleteSuggestion(WebInputElement(textField));
807
808    WebFrameImpl* webframe = WebFrameImpl::fromFrame(textField->document()->frame());
809    if (!webframe)
810        return;
811
812    webframe->notifiyPasswordListenerOfAutocomplete(WebInputElement(textField));
813}
814
815bool EditorClientImpl::doTextFieldCommandFromEvent(Element* element,
816                                                   KeyboardEvent* event)
817{
818    HTMLInputElement* inputElement = toHTMLInputElement(element);
819    if (m_webView->autoFillClient() && inputElement) {
820        m_webView->autoFillClient()->textFieldDidReceiveKeyDown(WebInputElement(inputElement),
821                                                                WebKeyboardEventBuilder(*event));
822    }
823
824    // Remember if backspace was pressed for the autofill.  It is not clear how to
825    // find if backspace was pressed from textFieldDidBeginEditing and
826    // textDidChangeInTextField as when these methods are called the value of the
827    // input element already contains the type character.
828    m_backspaceOrDeletePressed = event->keyCode() == VKEY_BACK || event->keyCode() == VKEY_DELETE;
829
830    // The Mac code appears to use this method as a hook to implement special
831    // keyboard commands specific to Safari's auto-fill implementation.  We
832    // just return false to allow the default action.
833    return false;
834}
835
836void EditorClientImpl::textWillBeDeletedInTextField(Element*)
837{
838}
839
840void EditorClientImpl::textDidChangeInTextArea(Element*)
841{
842}
843
844void EditorClientImpl::ignoreWordInSpellDocument(const String&)
845{
846    notImplemented();
847}
848
849void EditorClientImpl::learnWord(const String&)
850{
851    notImplemented();
852}
853
854void EditorClientImpl::checkSpellingOfString(const UChar* text, int length,
855                                             int* misspellingLocation,
856                                             int* misspellingLength)
857{
858    // SpellCheckWord will write (0, 0) into the output vars, which is what our
859    // caller expects if the word is spelled correctly.
860    int spellLocation = -1;
861    int spellLength = 0;
862
863    // Check to see if the provided text is spelled correctly.
864    if (isContinuousSpellCheckingEnabled() && m_webView->client())
865        m_webView->client()->spellCheck(WebString(text, length), spellLocation, spellLength);
866    else {
867        spellLocation = 0;
868        spellLength = 0;
869    }
870
871    // Note: the Mac code checks if the pointers are null before writing to them,
872    // so we do too.
873    if (misspellingLocation)
874        *misspellingLocation = spellLocation;
875    if (misspellingLength)
876        *misspellingLength = spellLength;
877}
878
879String EditorClientImpl::getAutoCorrectSuggestionForMisspelledWord(const String& misspelledWord)
880{
881    if (!(isContinuousSpellCheckingEnabled() && m_webView->client()))
882        return String();
883
884    // Do not autocorrect words with capital letters in it except the
885    // first letter. This will remove cases changing "IMB" to "IBM".
886    for (size_t i = 1; i < misspelledWord.length(); i++) {
887        if (u_isupper(static_cast<UChar32>(misspelledWord[i])))
888            return String();
889    }
890
891    return m_webView->client()->autoCorrectWord(WebString(misspelledWord));
892}
893
894void EditorClientImpl::checkGrammarOfString(const UChar*, int length,
895                                            WTF::Vector<GrammarDetail>&,
896                                            int* badGrammarLocation,
897                                            int* badGrammarLength)
898{
899    notImplemented();
900    if (badGrammarLocation)
901        *badGrammarLocation = 0;
902    if (badGrammarLength)
903        *badGrammarLength = 0;
904}
905
906void EditorClientImpl::updateSpellingUIWithGrammarString(const String&,
907                                                         const GrammarDetail& detail)
908{
909    notImplemented();
910}
911
912void EditorClientImpl::updateSpellingUIWithMisspelledWord(const String& misspelledWord)
913{
914    if (m_webView->client())
915        m_webView->client()->updateSpellingUIWithMisspelledWord(WebString(misspelledWord));
916}
917
918void EditorClientImpl::showSpellingUI(bool show)
919{
920    if (m_webView->client())
921        m_webView->client()->showSpellingUI(show);
922}
923
924bool EditorClientImpl::spellingUIIsShowing()
925{
926    if (m_webView->client())
927        return m_webView->client()->isShowingSpellingUI();
928    return false;
929}
930
931void EditorClientImpl::getGuessesForWord(const String& word,
932                                         const String& context,
933                                         WTF::Vector<String>& guesses)
934{
935    notImplemented();
936}
937
938void EditorClientImpl::willSetInputMethodState()
939{
940    if (m_webView->client())
941        m_webView->client()->resetInputMethod();
942}
943
944void EditorClientImpl::setInputMethodState(bool)
945{
946}
947
948} // namesace WebKit
949