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 63 using namespace WebCore; 64 65 namespace 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. 71 static 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). 75 static const size_t maximumTextSizeForAutofill = 1000; 76 77 EditorClientImpl::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 86 EditorClientImpl::~EditorClientImpl() 87 { 88 } 89 90 void EditorClientImpl::pageDestroyed() 91 { 92 // Our lifetime is bound to the WebViewImpl. 93 } 94 95 bool 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 104 bool EditorClientImpl::smartInsertDeleteEnabled() 105 { 106 if (m_webView->client()) 107 return m_webView->client()->isSmartInsertDeleteEnabled(); 108 return true; 109 } 110 111 bool 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 122 bool 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 153 bool EditorClientImpl::isContinuousSpellCheckingEnabled() 154 { 155 if (m_spellCheckThisFieldStatus == SpellCheckForcedOff) 156 return false; 157 if (m_spellCheckThisFieldStatus == SpellCheckForcedOn) 158 return true; 159 return shouldSpellcheckByDefault(); 160 } 161 162 void 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 175 bool EditorClientImpl::isGrammarCheckingEnabled() 176 { 177 return false; 178 } 179 180 void EditorClientImpl::toggleGrammarChecking() 181 { 182 notImplemented(); 183 } 184 185 int EditorClientImpl::spellCheckerDocumentTag() 186 { 187 ASSERT_NOT_REACHED(); 188 return 0; 189 } 190 191 bool EditorClientImpl::shouldBeginEditing(Range* range) 192 { 193 if (m_webView->client()) 194 return m_webView->client()->shouldBeginEditing(WebRange(range)); 195 return true; 196 } 197 198 bool EditorClientImpl::shouldEndEditing(Range* range) 199 { 200 if (m_webView->client()) 201 return m_webView->client()->shouldEndEditing(WebRange(range)); 202 return true; 203 } 204 205 bool 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 217 bool 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 230 bool EditorClientImpl::shouldDeleteRange(Range* range) 231 { 232 if (m_webView->client()) 233 return m_webView->client()->shouldDeleteRange(WebRange(range)); 234 return true; 235 } 236 237 bool 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 251 bool 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 262 bool EditorClientImpl::shouldMoveRangeAfterDelete(Range* range, 263 Range* rangeToBeReplaced) 264 { 265 return true; 266 } 267 268 void EditorClientImpl::didBeginEditing() 269 { 270 if (m_webView->client()) 271 m_webView->client()->didBeginEditing(); 272 } 273 274 void 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 283 void EditorClientImpl::respondToChangedContents() 284 { 285 if (m_webView->client()) 286 m_webView->client()->didChangeContents(); 287 } 288 289 void EditorClientImpl::didEndEditing() 290 { 291 if (m_webView->client()) 292 m_webView->client()->didEndEditing(); 293 } 294 295 void EditorClientImpl::didWriteSelectionToPasteboard() 296 { 297 } 298 299 void EditorClientImpl::didSetSelectionTypesForPasteboard() 300 { 301 } 302 303 void 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 312 void EditorClientImpl::registerCommandForRedo(PassRefPtr<EditCommand> command) 313 { 314 m_redoStack.append(command); 315 } 316 317 void EditorClientImpl::clearUndoRedoOperations() 318 { 319 m_undoStack.clear(); 320 m_redoStack.clear(); 321 } 322 323 bool EditorClientImpl::canCopyCut(bool defaultValue) const 324 { 325 return defaultValue; 326 } 327 328 bool EditorClientImpl::canPaste(bool defaultValue) const 329 { 330 return defaultValue; 331 } 332 333 bool EditorClientImpl::canUndo() const 334 { 335 return !m_undoStack.isEmpty(); 336 } 337 338 bool EditorClientImpl::canRedo() const 339 { 340 return !m_redoStack.isEmpty(); 341 } 342 343 void 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 354 void 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 373 static const unsigned CtrlKey = 1 << 0; 374 static const unsigned AltKey = 1 << 1; 375 static const unsigned ShiftKey = 1 << 2; 376 static 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. 380 static 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. 387 static const unsigned CommandKey = MetaKey; 388 #endif 389 390 // Keys with special meaning. These will be delegated to the editor using 391 // the execCommand() method 392 struct KeyDownEntry { 393 unsigned virtualKey; 394 unsigned modifiers; 395 const char* name; 396 }; 397 398 struct KeyPressEntry { 399 unsigned charCode; 400 unsigned modifiers; 401 const char* name; 402 }; 403 404 static 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 511 static 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 521 const 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 564 bool 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 644 void 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 659 void EditorClientImpl::handleInputMethodKeydown(KeyboardEvent* keyEvent) 660 { 661 // We handle IME within chrome. 662 } 663 664 void 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 671 void 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 705 void 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 717 bool 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 725 bool 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 768 void 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 805 void EditorClientImpl::cancelPendingAutofill() 806 { 807 m_autofillArgs.clear(); 808 m_autofillTimer.stop(); 809 } 810 811 bool 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 832 void EditorClientImpl::textWillBeDeletedInTextField(Element*) 833 { 834 } 835 836 void EditorClientImpl::textDidChangeInTextArea(Element*) 837 { 838 } 839 840 void EditorClientImpl::ignoreWordInSpellDocument(const String&) 841 { 842 notImplemented(); 843 } 844 845 void EditorClientImpl::learnWord(const String&) 846 { 847 notImplemented(); 848 } 849 850 void 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 875 void 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 881 String 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 898 void 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 910 void EditorClientImpl::updateSpellingUIWithGrammarString(const String&, 911 const GrammarDetail& detail) 912 { 913 notImplemented(); 914 } 915 916 void EditorClientImpl::updateSpellingUIWithMisspelledWord(const String& misspelledWord) 917 { 918 if (m_webView->spellCheckClient()) 919 m_webView->spellCheckClient()->updateSpellingUIWithMisspelledWord(WebString(misspelledWord)); 920 } 921 922 void EditorClientImpl::showSpellingUI(bool show) 923 { 924 if (m_webView->spellCheckClient()) 925 m_webView->spellCheckClient()->showSpellingUI(show); 926 } 927 928 bool EditorClientImpl::spellingUIIsShowing() 929 { 930 if (m_webView->spellCheckClient()) 931 return m_webView->spellCheckClient()->isShowingSpellingUI(); 932 return false; 933 } 934 935 void EditorClientImpl::getGuessesForWord(const String& word, 936 const String& context, 937 WTF::Vector<String>& guesses) 938 { 939 notImplemented(); 940 } 941 942 void EditorClientImpl::willSetInputMethodState() 943 { 944 if (m_webView->client()) 945 m_webView->client()->resetInputMethod(); 946 } 947 948 void EditorClientImpl::setInputMethodState(bool) 949 { 950 } 951 952 } // namesace WebKit 953