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