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