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