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