1 /* 2 * Copyright (C) 2006, 2007, 2008, 2011 Apple Inc. All rights reserved. 3 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) 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 "core/editing/Editor.h" 29 30 #include "CSSPropertyNames.h" 31 #include "HTMLNames.h" 32 #include "bindings/v8/ExceptionStatePlaceholder.h" 33 #include "core/accessibility/AXObjectCache.h" 34 #include "core/css/CSSComputedStyleDeclaration.h" 35 #include "core/css/StylePropertySet.h" 36 #include "core/dom/Clipboard.h" 37 #include "core/dom/ClipboardEvent.h" 38 #include "core/dom/DocumentFragment.h" 39 #include "core/dom/DocumentMarkerController.h" 40 #include "core/dom/EventNames.h" 41 #include "core/dom/KeyboardEvent.h" 42 #include "core/dom/NodeList.h" 43 #include "core/dom/NodeTraversal.h" 44 #include "core/dom/Text.h" 45 #include "core/dom/TextEvent.h" 46 #include "core/editing/ApplyStyleCommand.h" 47 #include "core/editing/DeleteSelectionCommand.h" 48 #include "core/editing/IndentOutdentCommand.h" 49 #include "core/editing/InputMethodController.h" 50 #include "core/editing/InsertListCommand.h" 51 #include "core/editing/ModifySelectionListLevel.h" 52 #include "core/editing/RemoveFormatCommand.h" 53 #include "core/editing/RenderedPosition.h" 54 #include "core/editing/ReplaceSelectionCommand.h" 55 #include "core/editing/SimplifyMarkupCommand.h" 56 #include "core/editing/SpellChecker.h" 57 #include "core/editing/TextCheckingHelper.h" 58 #include "core/editing/TextIterator.h" 59 #include "core/editing/TypingCommand.h" 60 #include "core/editing/VisibleUnits.h" 61 #include "core/editing/htmlediting.h" 62 #include "core/editing/markup.h" 63 #include "core/html/HTMLImageElement.h" 64 #include "core/html/HTMLInputElement.h" 65 #include "core/html/HTMLTextAreaElement.h" 66 #include "core/loader/cache/ResourceFetcher.h" 67 #include "core/page/EditorClient.h" 68 #include "core/page/EventHandler.h" 69 #include "core/page/FocusController.h" 70 #include "core/page/Frame.h" 71 #include "core/page/FrameView.h" 72 #include "core/page/Page.h" 73 #include "core/page/Settings.h" 74 #include "core/platform/KillRing.h" 75 #include "core/platform/Pasteboard.h" 76 #include "core/platform/Sound.h" 77 #include "core/platform/text/TextCheckerClient.h" 78 #include "core/rendering/HitTestResult.h" 79 #include "core/rendering/RenderBlock.h" 80 #include "core/rendering/RenderTextControl.h" 81 #include "wtf/unicode/CharacterNames.h" 82 83 namespace WebCore { 84 85 using namespace std; 86 using namespace HTMLNames; 87 using namespace WTF; 88 using namespace Unicode; 89 90 Editor::RevealSelectionScope::RevealSelectionScope(Editor* editor) 91 : m_editor(editor) 92 { 93 ++m_editor->m_preventRevealSelection; 94 } 95 96 Editor::RevealSelectionScope::~RevealSelectionScope() 97 { 98 ASSERT(m_editor->m_preventRevealSelection); 99 --m_editor->m_preventRevealSelection; 100 if (!m_editor->m_preventRevealSelection) 101 m_editor->m_frame->selection()->revealSelection(ScrollAlignment::alignToEdgeIfNeeded, RevealExtent); 102 } 103 104 namespace { 105 106 bool isSelectionInTextField(const VisibleSelection& selection) 107 { 108 HTMLTextFormControlElement* textControl = enclosingTextFormControl(selection.start()); 109 return textControl && textControl->hasTagName(inputTag) && toHTMLInputElement(textControl)->isTextField(); 110 } 111 112 } // namespace 113 114 // When an event handler has moved the selection outside of a text control 115 // we should use the target control's selection for this editing operation. 116 VisibleSelection Editor::selectionForCommand(Event* event) 117 { 118 VisibleSelection selection = m_frame->selection()->selection(); 119 if (!event) 120 return selection; 121 // If the target is a text control, and the current selection is outside of its shadow tree, 122 // then use the saved selection for that text control. 123 HTMLTextFormControlElement* textFormControlOfSelectionStart = enclosingTextFormControl(selection.start()); 124 HTMLTextFormControlElement* textFromControlOfTarget = isHTMLTextFormControlElement(event->target()->toNode()) ? toHTMLTextFormControlElement(event->target()->toNode()) : 0; 125 if (textFromControlOfTarget && (selection.start().isNull() || textFromControlOfTarget != textFormControlOfSelectionStart)) { 126 if (RefPtr<Range> range = textFromControlOfTarget->selection()) 127 return VisibleSelection(range.get(), DOWNSTREAM, selection.isDirectional()); 128 } 129 return selection; 130 } 131 132 // Function considers Mac editing behavior a fallback when Page or Settings is not available. 133 EditingBehavior Editor::behavior() const 134 { 135 if (!m_frame || !m_frame->settings()) 136 return EditingBehavior(EditingMacBehavior); 137 138 return EditingBehavior(m_frame->settings()->editingBehaviorType()); 139 } 140 141 EditorClient* Editor::client() const 142 { 143 if (Page* page = m_frame->page()) 144 return page->editorClient(); 145 return 0; 146 } 147 148 149 TextCheckerClient* Editor::textChecker() const 150 { 151 if (EditorClient* owner = client()) 152 return owner->textChecker(); 153 return 0; 154 } 155 156 void Editor::handleKeyboardEvent(KeyboardEvent* event) 157 { 158 if (EditorClient* c = client()) 159 c->handleKeyboardEvent(event); 160 } 161 162 bool Editor::handleTextEvent(TextEvent* event) 163 { 164 // Default event handling for Drag and Drop will be handled by DragController 165 // so we leave the event for it. 166 if (event->isDrop()) 167 return false; 168 169 if (event->isPaste()) { 170 if (event->pastingFragment()) 171 replaceSelectionWithFragment(event->pastingFragment(), false, event->shouldSmartReplace(), event->shouldMatchStyle()); 172 else 173 replaceSelectionWithText(event->data(), false, event->shouldSmartReplace()); 174 return true; 175 } 176 177 String data = event->data(); 178 if (data == "\n") { 179 if (event->isLineBreak()) 180 return insertLineBreak(); 181 return insertParagraphSeparator(); 182 } 183 184 return insertTextWithoutSendingTextEvent(data, false, event); 185 } 186 187 bool Editor::canEdit() const 188 { 189 return m_frame->selection()->rootEditableElement(); 190 } 191 192 bool Editor::canEditRichly() const 193 { 194 return m_frame->selection()->isContentRichlyEditable(); 195 } 196 197 // WinIE uses onbeforecut and onbeforepaste to enables the cut and paste menu items. They 198 // also send onbeforecopy, apparently for symmetry, but it doesn't affect the menu items. 199 // We need to use onbeforecopy as a real menu enabler because we allow elements that are not 200 // normally selectable to implement copy/paste (like divs, or a document body). 201 202 bool Editor::canDHTMLCut() 203 { 204 return !m_frame->selection()->isInPasswordField() && !dispatchCPPEvent(eventNames().beforecutEvent, ClipboardNumb); 205 } 206 207 bool Editor::canDHTMLCopy() 208 { 209 return !m_frame->selection()->isInPasswordField() && !dispatchCPPEvent(eventNames().beforecopyEvent, ClipboardNumb); 210 } 211 212 bool Editor::canDHTMLPaste() 213 { 214 return !dispatchCPPEvent(eventNames().beforepasteEvent, ClipboardNumb); 215 } 216 217 bool Editor::canCut() const 218 { 219 return canCopy() && canDelete(); 220 } 221 222 static HTMLImageElement* imageElementFromImageDocument(Document* document) 223 { 224 if (!document) 225 return 0; 226 if (!document->isImageDocument()) 227 return 0; 228 229 HTMLElement* body = document->body(); 230 if (!body) 231 return 0; 232 233 Node* node = body->firstChild(); 234 if (!node) 235 return 0; 236 if (!node->hasTagName(imgTag)) 237 return 0; 238 return toHTMLImageElement(node); 239 } 240 241 bool Editor::canCopy() const 242 { 243 if (imageElementFromImageDocument(m_frame->document())) 244 return true; 245 FrameSelection* selection = m_frame->selection(); 246 return selection->isRange() && !selection->isInPasswordField(); 247 } 248 249 bool Editor::canPaste() const 250 { 251 return canEdit(); 252 } 253 254 bool Editor::canDelete() const 255 { 256 FrameSelection* selection = m_frame->selection(); 257 return selection->isRange() && selection->rootEditableElement(); 258 } 259 260 bool Editor::canDeleteRange(Range* range) const 261 { 262 Node* startContainer = range->startContainer(); 263 Node* endContainer = range->endContainer(); 264 if (!startContainer || !endContainer) 265 return false; 266 267 if (!startContainer->rendererIsEditable() || !endContainer->rendererIsEditable()) 268 return false; 269 270 if (range->collapsed(IGNORE_EXCEPTION)) { 271 VisiblePosition start(range->startPosition(), DOWNSTREAM); 272 VisiblePosition previous = start.previous(); 273 // FIXME: We sometimes allow deletions at the start of editable roots, like when the caret is in an empty list item. 274 if (previous.isNull() || previous.deepEquivalent().deprecatedNode()->rootEditableElement() != startContainer->rootEditableElement()) 275 return false; 276 } 277 return true; 278 } 279 280 bool Editor::smartInsertDeleteEnabled() 281 { 282 return client() && client()->smartInsertDeleteEnabled(); 283 } 284 285 bool Editor::canSmartCopyOrDelete() 286 { 287 return client() && client()->smartInsertDeleteEnabled() && m_frame->selection()->granularity() == WordGranularity; 288 } 289 290 bool Editor::isSelectTrailingWhitespaceEnabled() 291 { 292 return client() && client()->isSelectTrailingWhitespaceEnabled(); 293 } 294 295 bool Editor::deleteWithDirection(SelectionDirection direction, TextGranularity granularity, bool killRing, bool isTypingAction) 296 { 297 if (!canEdit()) 298 return false; 299 300 if (m_frame->selection()->isRange()) { 301 if (isTypingAction) { 302 TypingCommand::deleteKeyPressed(m_frame->document(), canSmartCopyOrDelete() ? TypingCommand::SmartDelete : 0, granularity); 303 revealSelectionAfterEditingOperation(); 304 } else { 305 if (killRing) 306 addToKillRing(selectedRange().get(), false); 307 deleteSelectionWithSmartDelete(canSmartCopyOrDelete()); 308 // Implicitly calls revealSelectionAfterEditingOperation(). 309 } 310 } else { 311 TypingCommand::Options options = 0; 312 if (canSmartCopyOrDelete()) 313 options |= TypingCommand::SmartDelete; 314 if (killRing) 315 options |= TypingCommand::KillRing; 316 switch (direction) { 317 case DirectionForward: 318 case DirectionRight: 319 TypingCommand::forwardDeleteKeyPressed(m_frame->document(), options, granularity); 320 break; 321 case DirectionBackward: 322 case DirectionLeft: 323 TypingCommand::deleteKeyPressed(m_frame->document(), options, granularity); 324 break; 325 } 326 revealSelectionAfterEditingOperation(); 327 } 328 329 // FIXME: We should to move this down into deleteKeyPressed. 330 // clear the "start new kill ring sequence" setting, because it was set to true 331 // when the selection was updated by deleting the range 332 if (killRing) 333 setStartNewKillRingSequence(false); 334 335 return true; 336 } 337 338 void Editor::deleteSelectionWithSmartDelete(bool smartDelete) 339 { 340 if (m_frame->selection()->isNone()) 341 return; 342 343 applyCommand(DeleteSelectionCommand::create(m_frame->document(), smartDelete)); 344 } 345 346 void Editor::pasteAsPlainText(const String& pastingText, bool smartReplace) 347 { 348 Node* target = findEventTargetFromSelection(); 349 if (!target) 350 return; 351 target->dispatchEvent(TextEvent::createForPlainTextPaste(m_frame->domWindow(), pastingText, smartReplace), IGNORE_EXCEPTION); 352 } 353 354 void Editor::pasteAsFragment(PassRefPtr<DocumentFragment> pastingFragment, bool smartReplace, bool matchStyle) 355 { 356 Node* target = findEventTargetFromSelection(); 357 if (!target) 358 return; 359 target->dispatchEvent(TextEvent::createForFragmentPaste(m_frame->domWindow(), pastingFragment, smartReplace, matchStyle), IGNORE_EXCEPTION); 360 } 361 362 void Editor::pasteAsPlainTextBypassingDHTML() 363 { 364 pasteAsPlainTextWithPasteboard(Pasteboard::generalPasteboard()); 365 } 366 367 void Editor::pasteAsPlainTextWithPasteboard(Pasteboard* pasteboard) 368 { 369 String text = pasteboard->plainText(m_frame); 370 if (client() && client()->shouldInsertText(text, selectedRange().get(), EditorInsertActionPasted)) 371 pasteAsPlainText(text, canSmartReplaceWithPasteboard(pasteboard)); 372 } 373 374 void Editor::pasteWithPasteboard(Pasteboard* pasteboard, bool allowPlainText) 375 { 376 RefPtr<Range> range = selectedRange(); 377 bool chosePlainText; 378 RefPtr<DocumentFragment> fragment = pasteboard->documentFragment(m_frame, range, allowPlainText, chosePlainText); 379 if (fragment && shouldInsertFragment(fragment, range, EditorInsertActionPasted)) 380 pasteAsFragment(fragment, canSmartReplaceWithPasteboard(pasteboard), chosePlainText); 381 } 382 383 bool Editor::canSmartReplaceWithPasteboard(Pasteboard* pasteboard) 384 { 385 return client() && client()->smartInsertDeleteEnabled() && pasteboard->canSmartReplace(); 386 } 387 388 bool Editor::shouldInsertFragment(PassRefPtr<DocumentFragment> fragment, PassRefPtr<Range> replacingDOMRange, EditorInsertAction givenAction) 389 { 390 if (!client()) 391 return false; 392 393 if (fragment) { 394 Node* child = fragment->firstChild(); 395 if (child && fragment->lastChild() == child && child->isCharacterDataNode()) 396 return client()->shouldInsertText(static_cast<CharacterData*>(child)->data(), replacingDOMRange.get(), givenAction); 397 } 398 399 return client()->shouldInsertNode(fragment.get(), replacingDOMRange.get(), givenAction); 400 } 401 402 void Editor::replaceSelectionWithFragment(PassRefPtr<DocumentFragment> fragment, bool selectReplacement, bool smartReplace, bool matchStyle) 403 { 404 if (m_frame->selection()->isNone() || !m_frame->selection()->isContentEditable() || !fragment) 405 return; 406 407 ReplaceSelectionCommand::CommandOptions options = ReplaceSelectionCommand::PreventNesting | ReplaceSelectionCommand::SanitizeFragment; 408 if (selectReplacement) 409 options |= ReplaceSelectionCommand::SelectReplacement; 410 if (smartReplace) 411 options |= ReplaceSelectionCommand::SmartReplace; 412 if (matchStyle) 413 options |= ReplaceSelectionCommand::MatchStyle; 414 applyCommand(ReplaceSelectionCommand::create(m_frame->document(), fragment, options, EditActionPaste)); 415 revealSelectionAfterEditingOperation(); 416 417 if (m_frame->selection()->isInPasswordField() || !isContinuousSpellCheckingEnabled()) 418 return; 419 Node* nodeToCheck = m_frame->selection()->rootEditableElement(); 420 if (!nodeToCheck) 421 return; 422 423 RefPtr<Range> rangeToCheck = Range::create(m_frame->document(), firstPositionInNode(nodeToCheck), lastPositionInNode(nodeToCheck)); 424 m_spellChecker->requestCheckingFor(SpellCheckRequest::create(resolveTextCheckingTypeMask(TextCheckingTypeSpelling | TextCheckingTypeGrammar), TextCheckingProcessBatch, rangeToCheck, rangeToCheck)); 425 } 426 427 void Editor::replaceSelectionWithText(const String& text, bool selectReplacement, bool smartReplace) 428 { 429 replaceSelectionWithFragment(createFragmentFromText(selectedRange().get(), text), selectReplacement, smartReplace, true); 430 } 431 432 PassRefPtr<Range> Editor::selectedRange() 433 { 434 if (!m_frame) 435 return 0; 436 return m_frame->selection()->toNormalizedRange(); 437 } 438 439 bool Editor::shouldDeleteRange(Range* range) const 440 { 441 if (!range || range->collapsed(IGNORE_EXCEPTION)) 442 return false; 443 444 if (!canDeleteRange(range)) 445 return false; 446 447 return client() && client()->shouldDeleteRange(range); 448 } 449 450 bool Editor::tryDHTMLCopy() 451 { 452 if (m_frame->selection()->isInPasswordField()) 453 return false; 454 455 return !dispatchCPPEvent(eventNames().copyEvent, ClipboardWritable); 456 } 457 458 bool Editor::tryDHTMLCut() 459 { 460 if (m_frame->selection()->isInPasswordField()) 461 return false; 462 463 return !dispatchCPPEvent(eventNames().cutEvent, ClipboardWritable); 464 } 465 466 bool Editor::tryDHTMLPaste() 467 { 468 return !dispatchCPPEvent(eventNames().pasteEvent, ClipboardReadable); 469 } 470 471 bool Editor::shouldInsertText(const String& text, Range* range, EditorInsertAction action) const 472 { 473 return client() && client()->shouldInsertText(text, range, action); 474 } 475 476 void Editor::notifyComponentsOnChangedSelection(const VisibleSelection& oldSelection, FrameSelection::SetSelectionOptions options) 477 { 478 if (client()) 479 client()->respondToChangedSelection(m_frame); 480 setStartNewKillRingSequence(true); 481 } 482 483 void Editor::respondToChangedContents(const VisibleSelection& endingSelection) 484 { 485 if (AXObjectCache::accessibilityEnabled()) { 486 Node* node = endingSelection.start().deprecatedNode(); 487 if (AXObjectCache* cache = m_frame->document()->existingAXObjectCache()) 488 cache->postNotification(node, AXObjectCache::AXValueChanged, false); 489 } 490 491 updateMarkersForWordsAffectedByEditing(true); 492 493 if (client()) 494 client()->respondToChangedContents(); 495 } 496 497 TriState Editor::selectionUnorderedListState() const 498 { 499 if (m_frame->selection()->isCaret()) { 500 if (enclosingNodeWithTag(m_frame->selection()->selection().start(), ulTag)) 501 return TrueTriState; 502 } else if (m_frame->selection()->isRange()) { 503 Node* startNode = enclosingNodeWithTag(m_frame->selection()->selection().start(), ulTag); 504 Node* endNode = enclosingNodeWithTag(m_frame->selection()->selection().end(), ulTag); 505 if (startNode && endNode && startNode == endNode) 506 return TrueTriState; 507 } 508 509 return FalseTriState; 510 } 511 512 TriState Editor::selectionOrderedListState() const 513 { 514 if (m_frame->selection()->isCaret()) { 515 if (enclosingNodeWithTag(m_frame->selection()->selection().start(), olTag)) 516 return TrueTriState; 517 } else if (m_frame->selection()->isRange()) { 518 Node* startNode = enclosingNodeWithTag(m_frame->selection()->selection().start(), olTag); 519 Node* endNode = enclosingNodeWithTag(m_frame->selection()->selection().end(), olTag); 520 if (startNode && endNode && startNode == endNode) 521 return TrueTriState; 522 } 523 524 return FalseTriState; 525 } 526 527 PassRefPtr<Node> Editor::insertOrderedList() 528 { 529 if (!canEditRichly()) 530 return 0; 531 532 RefPtr<Node> newList = InsertListCommand::insertList(m_frame->document(), InsertListCommand::OrderedList); 533 revealSelectionAfterEditingOperation(); 534 return newList; 535 } 536 537 PassRefPtr<Node> Editor::insertUnorderedList() 538 { 539 if (!canEditRichly()) 540 return 0; 541 542 RefPtr<Node> newList = InsertListCommand::insertList(m_frame->document(), InsertListCommand::UnorderedList); 543 revealSelectionAfterEditingOperation(); 544 return newList; 545 } 546 547 bool Editor::canIncreaseSelectionListLevel() 548 { 549 return canEditRichly() && IncreaseSelectionListLevelCommand::canIncreaseSelectionListLevel(m_frame->document()); 550 } 551 552 bool Editor::canDecreaseSelectionListLevel() 553 { 554 return canEditRichly() && DecreaseSelectionListLevelCommand::canDecreaseSelectionListLevel(m_frame->document()); 555 } 556 557 PassRefPtr<Node> Editor::increaseSelectionListLevel() 558 { 559 if (!canEditRichly() || m_frame->selection()->isNone()) 560 return 0; 561 562 RefPtr<Node> newList = IncreaseSelectionListLevelCommand::increaseSelectionListLevel(m_frame->document()); 563 revealSelectionAfterEditingOperation(); 564 return newList; 565 } 566 567 PassRefPtr<Node> Editor::increaseSelectionListLevelOrdered() 568 { 569 if (!canEditRichly() || m_frame->selection()->isNone()) 570 return 0; 571 572 RefPtr<Node> newList = IncreaseSelectionListLevelCommand::increaseSelectionListLevelOrdered(m_frame->document()); 573 revealSelectionAfterEditingOperation(); 574 return newList.release(); 575 } 576 577 PassRefPtr<Node> Editor::increaseSelectionListLevelUnordered() 578 { 579 if (!canEditRichly() || m_frame->selection()->isNone()) 580 return 0; 581 582 RefPtr<Node> newList = IncreaseSelectionListLevelCommand::increaseSelectionListLevelUnordered(m_frame->document()); 583 revealSelectionAfterEditingOperation(); 584 return newList.release(); 585 } 586 587 void Editor::decreaseSelectionListLevel() 588 { 589 if (!canEditRichly() || m_frame->selection()->isNone()) 590 return; 591 592 DecreaseSelectionListLevelCommand::decreaseSelectionListLevel(m_frame->document()); 593 revealSelectionAfterEditingOperation(); 594 } 595 596 void Editor::removeFormattingAndStyle() 597 { 598 applyCommand(RemoveFormatCommand::create(m_frame->document())); 599 } 600 601 void Editor::clearLastEditCommand() 602 { 603 m_lastEditCommand.clear(); 604 } 605 606 // Returns whether caller should continue with "the default processing", which is the same as 607 // the event handler NOT setting the return value to false 608 bool Editor::dispatchCPPEvent(const AtomicString &eventType, ClipboardAccessPolicy policy) 609 { 610 Node* target = findEventTargetFromSelection(); 611 if (!target) 612 return true; 613 614 RefPtr<Clipboard> clipboard = newGeneralClipboard(policy, m_frame); 615 616 RefPtr<Event> evt = ClipboardEvent::create(eventType, true, true, clipboard); 617 target->dispatchEvent(evt, IGNORE_EXCEPTION); 618 bool noDefaultProcessing = evt->defaultPrevented(); 619 if (noDefaultProcessing && policy == ClipboardWritable) { 620 Pasteboard* pasteboard = Pasteboard::generalPasteboard(); 621 pasteboard->clear(); 622 pasteboard->writeClipboard(clipboard.get()); 623 } 624 625 // invalidate clipboard here for security 626 clipboard->setAccessPolicy(ClipboardNumb); 627 628 return !noDefaultProcessing; 629 } 630 631 Node* Editor::findEventTargetFrom(const VisibleSelection& selection) const 632 { 633 Node* target = selection.start().element(); 634 if (!target) 635 target = m_frame->document()->body(); 636 if (!target) 637 return 0; 638 639 return target; 640 } 641 642 Node* Editor::findEventTargetFromSelection() const 643 { 644 return findEventTargetFrom(m_frame->selection()->selection()); 645 } 646 647 void Editor::applyStyle(StylePropertySet* style, EditAction editingAction) 648 { 649 switch (m_frame->selection()->selectionType()) { 650 case VisibleSelection::NoSelection: 651 // do nothing 652 break; 653 case VisibleSelection::CaretSelection: 654 computeAndSetTypingStyle(style, editingAction); 655 break; 656 case VisibleSelection::RangeSelection: 657 if (style) 658 applyCommand(ApplyStyleCommand::create(m_frame->document(), EditingStyle::create(style).get(), editingAction)); 659 break; 660 } 661 } 662 663 bool Editor::shouldApplyStyle(StylePropertySet* style, Range* range) 664 { 665 return client()->shouldApplyStyle(style, range); 666 } 667 668 void Editor::applyParagraphStyle(StylePropertySet* style, EditAction editingAction) 669 { 670 switch (m_frame->selection()->selectionType()) { 671 case VisibleSelection::NoSelection: 672 // do nothing 673 break; 674 case VisibleSelection::CaretSelection: 675 case VisibleSelection::RangeSelection: 676 if (style) 677 applyCommand(ApplyStyleCommand::create(m_frame->document(), EditingStyle::create(style).get(), editingAction, ApplyStyleCommand::ForceBlockProperties)); 678 break; 679 } 680 } 681 682 void Editor::applyStyleToSelection(StylePropertySet* style, EditAction editingAction) 683 { 684 if (!style || style->isEmpty() || !canEditRichly()) 685 return; 686 687 if (client() && client()->shouldApplyStyle(style, m_frame->selection()->toNormalizedRange().get())) 688 applyStyle(style, editingAction); 689 } 690 691 void Editor::applyParagraphStyleToSelection(StylePropertySet* style, EditAction editingAction) 692 { 693 if (!style || style->isEmpty() || !canEditRichly()) 694 return; 695 696 if (client() && client()->shouldApplyStyle(style, m_frame->selection()->toNormalizedRange().get())) 697 applyParagraphStyle(style, editingAction); 698 } 699 700 bool Editor::selectionStartHasStyle(CSSPropertyID propertyID, const String& value) const 701 { 702 return EditingStyle::create(propertyID, value)->triStateOfStyle( 703 EditingStyle::styleAtSelectionStart(m_frame->selection()->selection(), propertyID == CSSPropertyBackgroundColor).get()); 704 } 705 706 TriState Editor::selectionHasStyle(CSSPropertyID propertyID, const String& value) const 707 { 708 return EditingStyle::create(propertyID, value)->triStateOfStyle(m_frame->selection()->selection()); 709 } 710 711 String Editor::selectionStartCSSPropertyValue(CSSPropertyID propertyID) 712 { 713 RefPtr<EditingStyle> selectionStyle = EditingStyle::styleAtSelectionStart(m_frame->selection()->selection(), 714 propertyID == CSSPropertyBackgroundColor); 715 if (!selectionStyle || !selectionStyle->style()) 716 return String(); 717 718 if (propertyID == CSSPropertyFontSize) 719 return String::number(selectionStyle->legacyFontSize(m_frame->document())); 720 return selectionStyle->style()->getPropertyValue(propertyID); 721 } 722 723 void Editor::indent() 724 { 725 applyCommand(IndentOutdentCommand::create(m_frame->document(), IndentOutdentCommand::Indent)); 726 } 727 728 void Editor::outdent() 729 { 730 applyCommand(IndentOutdentCommand::create(m_frame->document(), IndentOutdentCommand::Outdent)); 731 } 732 733 static void dispatchEditableContentChangedEvents(PassRefPtr<Element> startRoot, PassRefPtr<Element> endRoot) 734 { 735 if (startRoot) 736 startRoot->dispatchEvent(Event::create(eventNames().webkitEditableContentChangedEvent, false, false), IGNORE_EXCEPTION); 737 if (endRoot && endRoot != startRoot) 738 endRoot->dispatchEvent(Event::create(eventNames().webkitEditableContentChangedEvent, false, false), IGNORE_EXCEPTION); 739 } 740 741 void Editor::appliedEditing(PassRefPtr<CompositeEditCommand> cmd) 742 { 743 m_frame->document()->updateLayout(); 744 745 EditCommandComposition* composition = cmd->composition(); 746 ASSERT(composition); 747 VisibleSelection newSelection(cmd->endingSelection()); 748 749 // Don't clear the typing style with this selection change. We do those things elsewhere if necessary. 750 changeSelectionAfterCommand(newSelection, 0); 751 dispatchEditableContentChangedEvents(composition->startingRootEditableElement(), composition->endingRootEditableElement()); 752 753 if (!cmd->preservesTypingStyle()) 754 m_frame->selection()->clearTypingStyle(); 755 756 // Command will be equal to last edit command only in the case of typing 757 if (m_lastEditCommand.get() == cmd) 758 ASSERT(cmd->isTypingCommand()); 759 else { 760 // Only register a new undo command if the command passed in is 761 // different from the last command 762 m_lastEditCommand = cmd; 763 if (client()) 764 client()->registerUndoStep(m_lastEditCommand->ensureComposition()); 765 } 766 767 respondToChangedContents(newSelection); 768 } 769 770 void Editor::unappliedEditing(PassRefPtr<EditCommandComposition> cmd) 771 { 772 m_frame->document()->updateLayout(); 773 774 VisibleSelection newSelection(cmd->startingSelection()); 775 changeSelectionAfterCommand(newSelection, FrameSelection::CloseTyping | FrameSelection::ClearTypingStyle); 776 dispatchEditableContentChangedEvents(cmd->startingRootEditableElement(), cmd->endingRootEditableElement()); 777 778 m_lastEditCommand = 0; 779 if (client()) 780 client()->registerRedoStep(cmd); 781 respondToChangedContents(newSelection); 782 } 783 784 void Editor::reappliedEditing(PassRefPtr<EditCommandComposition> cmd) 785 { 786 m_frame->document()->updateLayout(); 787 788 VisibleSelection newSelection(cmd->endingSelection()); 789 changeSelectionAfterCommand(newSelection, FrameSelection::CloseTyping | FrameSelection::ClearTypingStyle); 790 dispatchEditableContentChangedEvents(cmd->startingRootEditableElement(), cmd->endingRootEditableElement()); 791 792 m_lastEditCommand = 0; 793 if (client()) 794 client()->registerUndoStep(cmd); 795 respondToChangedContents(newSelection); 796 } 797 798 Editor::Editor(Frame* frame) 799 : FrameDestructionObserver(frame) 800 , m_preventRevealSelection(0) 801 , m_shouldStartNewKillRingSequence(false) 802 // This is off by default, since most editors want this behavior (this matches IE but not FF). 803 , m_shouldStyleWithCSS(false) 804 , m_killRing(adoptPtr(new KillRing)) 805 , m_spellChecker(adoptPtr(new SpellChecker(frame))) 806 , m_areMarkedTextMatchesHighlighted(false) 807 , m_defaultParagraphSeparator(EditorParagraphSeparatorIsDiv) 808 , m_overwriteModeEnabled(false) 809 { 810 } 811 812 Editor::~Editor() 813 { 814 } 815 816 void Editor::clear() 817 { 818 m_frame->inputMethodController().clear(); 819 m_shouldStyleWithCSS = false; 820 m_defaultParagraphSeparator = EditorParagraphSeparatorIsDiv; 821 } 822 823 bool Editor::insertText(const String& text, Event* triggeringEvent) 824 { 825 return m_frame->eventHandler()->handleTextInputEvent(text, triggeringEvent); 826 } 827 828 bool Editor::insertTextWithoutSendingTextEvent(const String& text, bool selectInsertedText, TextEvent* triggeringEvent) 829 { 830 if (text.isEmpty()) 831 return false; 832 833 VisibleSelection selection = selectionForCommand(triggeringEvent); 834 if (!selection.isContentEditable()) 835 return false; 836 RefPtr<Range> range = selection.toNormalizedRange(); 837 838 if (!shouldInsertText(text, range.get(), EditorInsertActionTyped)) 839 return true; 840 841 if (!text.isEmpty()) 842 updateMarkersForWordsAffectedByEditing(isSpaceOrNewline(text[0])); 843 844 // Get the selection to use for the event that triggered this insertText. 845 // If the event handler changed the selection, we may want to use a different selection 846 // that is contained in the event target. 847 selection = selectionForCommand(triggeringEvent); 848 if (selection.isContentEditable()) { 849 if (Node* selectionStart = selection.start().deprecatedNode()) { 850 RefPtr<Document> document = selectionStart->document(); 851 852 // Insert the text 853 TypingCommand::Options options = 0; 854 if (selectInsertedText) 855 options |= TypingCommand::SelectInsertedText; 856 TypingCommand::insertText(document.get(), text, selection, options, triggeringEvent && triggeringEvent->isComposition() ? TypingCommand::TextCompositionConfirm : TypingCommand::TextCompositionNone); 857 858 // Reveal the current selection 859 if (Frame* editedFrame = document->frame()) { 860 if (Page* page = editedFrame->page()) 861 page->focusController().focusedOrMainFrame()->selection()->revealSelection(ScrollAlignment::alignCenterIfNeeded); 862 } 863 } 864 } 865 866 return true; 867 } 868 869 bool Editor::insertLineBreak() 870 { 871 if (!canEdit()) 872 return false; 873 874 if (!shouldInsertText("\n", m_frame->selection()->toNormalizedRange().get(), EditorInsertActionTyped)) 875 return true; 876 877 VisiblePosition caret = m_frame->selection()->selection().visibleStart(); 878 bool alignToEdge = isEndOfEditableOrNonEditableContent(caret); 879 TypingCommand::insertLineBreak(m_frame->document(), 0); 880 revealSelectionAfterEditingOperation(alignToEdge ? ScrollAlignment::alignToEdgeIfNeeded : ScrollAlignment::alignCenterIfNeeded); 881 882 return true; 883 } 884 885 bool Editor::insertParagraphSeparator() 886 { 887 if (!canEdit()) 888 return false; 889 890 if (!canEditRichly()) 891 return insertLineBreak(); 892 893 if (!shouldInsertText("\n", m_frame->selection()->toNormalizedRange().get(), EditorInsertActionTyped)) 894 return true; 895 896 VisiblePosition caret = m_frame->selection()->selection().visibleStart(); 897 bool alignToEdge = isEndOfEditableOrNonEditableContent(caret); 898 TypingCommand::insertParagraphSeparator(m_frame->document(), 0); 899 revealSelectionAfterEditingOperation(alignToEdge ? ScrollAlignment::alignToEdgeIfNeeded : ScrollAlignment::alignCenterIfNeeded); 900 901 return true; 902 } 903 904 void Editor::cut() 905 { 906 if (tryDHTMLCut()) 907 return; // DHTML did the whole operation 908 if (!canCut()) { 909 systemBeep(); 910 return; 911 } 912 RefPtr<Range> selection = selectedRange(); 913 if (shouldDeleteRange(selection.get())) { 914 updateMarkersForWordsAffectedByEditing(true); 915 if (enclosingTextFormControl(m_frame->selection()->start())) { 916 Pasteboard::generalPasteboard()->writePlainText(m_frame->selectedTextForClipboard(), 917 canSmartCopyOrDelete() ? Pasteboard::CanSmartReplace : Pasteboard::CannotSmartReplace); 918 } else 919 Pasteboard::generalPasteboard()->writeSelection(selection.get(), canSmartCopyOrDelete(), m_frame, IncludeImageAltTextForClipboard); 920 deleteSelectionWithSmartDelete(canSmartCopyOrDelete()); 921 } 922 } 923 924 void Editor::copy() 925 { 926 if (tryDHTMLCopy()) 927 return; // DHTML did the whole operation 928 if (!canCopy()) { 929 systemBeep(); 930 return; 931 } 932 933 if (enclosingTextFormControl(m_frame->selection()->start())) { 934 Pasteboard::generalPasteboard()->writePlainText(m_frame->selectedTextForClipboard(), 935 canSmartCopyOrDelete() ? Pasteboard::CanSmartReplace : Pasteboard::CannotSmartReplace); 936 } else { 937 Document* document = m_frame->document(); 938 if (HTMLImageElement* imageElement = imageElementFromImageDocument(document)) 939 Pasteboard::generalPasteboard()->writeImage(imageElement, document->url(), document->title()); 940 else 941 Pasteboard::generalPasteboard()->writeSelection(selectedRange().get(), canSmartCopyOrDelete(), m_frame, IncludeImageAltTextForClipboard); 942 } 943 } 944 945 void Editor::paste() 946 { 947 ASSERT(m_frame->document()); 948 if (tryDHTMLPaste()) 949 return; // DHTML did the whole operation 950 if (!canPaste()) 951 return; 952 updateMarkersForWordsAffectedByEditing(false); 953 ResourceFetcher* loader = m_frame->document()->fetcher(); 954 ResourceCacheValidationSuppressor validationSuppressor(loader); 955 if (m_frame->selection()->isContentRichlyEditable()) 956 pasteWithPasteboard(Pasteboard::generalPasteboard(), true); 957 else 958 pasteAsPlainTextWithPasteboard(Pasteboard::generalPasteboard()); 959 } 960 961 void Editor::pasteAsPlainText() 962 { 963 if (tryDHTMLPaste()) 964 return; 965 if (!canPaste()) 966 return; 967 updateMarkersForWordsAffectedByEditing(false); 968 pasteAsPlainTextWithPasteboard(Pasteboard::generalPasteboard()); 969 } 970 971 void Editor::performDelete() 972 { 973 if (!canDelete()) { 974 systemBeep(); 975 return; 976 } 977 978 addToKillRing(selectedRange().get(), false); 979 deleteSelectionWithSmartDelete(canSmartCopyOrDelete()); 980 981 // clear the "start new kill ring sequence" setting, because it was set to true 982 // when the selection was updated by deleting the range 983 setStartNewKillRingSequence(false); 984 } 985 986 void Editor::simplifyMarkup(Node* startNode, Node* endNode) 987 { 988 if (!startNode) 989 return; 990 if (endNode) { 991 if (startNode->document() != endNode->document()) 992 return; 993 // check if start node is before endNode 994 Node* node = startNode; 995 while (node && node != endNode) 996 node = NodeTraversal::next(node); 997 if (!node) 998 return; 999 } 1000 1001 applyCommand(SimplifyMarkupCommand::create(m_frame->document(), startNode, (endNode) ? NodeTraversal::next(endNode) : 0)); 1002 } 1003 1004 void Editor::copyURL(const KURL& url, const String& title) 1005 { 1006 Pasteboard::generalPasteboard()->writeURL(url, title, m_frame); 1007 } 1008 1009 void Editor::copyImage(const HitTestResult& result) 1010 { 1011 KURL url = result.absoluteLinkURL(); 1012 if (url.isEmpty()) 1013 url = result.absoluteImageURL(); 1014 1015 Pasteboard::generalPasteboard()->writeImage(result.innerNonSharedNode(), url, result.altDisplayString()); 1016 } 1017 1018 bool Editor::isContinuousSpellCheckingEnabled() const 1019 { 1020 return client() && client()->isContinuousSpellCheckingEnabled(); 1021 } 1022 1023 void Editor::toggleContinuousSpellChecking() 1024 { 1025 if (client()) 1026 client()->toggleContinuousSpellChecking(); 1027 } 1028 1029 bool Editor::isGrammarCheckingEnabled() 1030 { 1031 return client() && client()->isGrammarCheckingEnabled(); 1032 } 1033 1034 bool Editor::shouldEndEditing(Range* range) 1035 { 1036 return client() && client()->shouldEndEditing(range); 1037 } 1038 1039 bool Editor::shouldBeginEditing(Range* range) 1040 { 1041 return client() && client()->shouldBeginEditing(range); 1042 } 1043 1044 void Editor::clearUndoRedoOperations() 1045 { 1046 if (client()) 1047 client()->clearUndoRedoOperations(); 1048 } 1049 1050 bool Editor::canUndo() 1051 { 1052 return client() && client()->canUndo(); 1053 } 1054 1055 void Editor::undo() 1056 { 1057 if (client()) 1058 client()->undo(); 1059 } 1060 1061 bool Editor::canRedo() 1062 { 1063 return client() && client()->canRedo(); 1064 } 1065 1066 void Editor::redo() 1067 { 1068 if (client()) 1069 client()->redo(); 1070 } 1071 1072 void Editor::didBeginEditing() 1073 { 1074 if (client()) 1075 client()->didBeginEditing(); 1076 } 1077 1078 void Editor::didEndEditing() 1079 { 1080 if (client()) 1081 client()->didEndEditing(); 1082 } 1083 1084 void Editor::setBaseWritingDirection(WritingDirection direction) 1085 { 1086 Node* focusedElement = frame()->document()->focusedElement(); 1087 if (focusedElement && isHTMLTextFormControlElement(focusedElement)) { 1088 if (direction == NaturalWritingDirection) 1089 return; 1090 toHTMLElement(focusedElement)->setAttribute(dirAttr, direction == LeftToRightWritingDirection ? "ltr" : "rtl"); 1091 focusedElement->dispatchInputEvent(); 1092 frame()->document()->updateStyleIfNeeded(); 1093 return; 1094 } 1095 1096 RefPtr<MutableStylePropertySet> style = MutableStylePropertySet::create(); 1097 style->setProperty(CSSPropertyDirection, direction == LeftToRightWritingDirection ? "ltr" : direction == RightToLeftWritingDirection ? "rtl" : "inherit", false); 1098 applyParagraphStyleToSelection(style.get(), EditActionSetWritingDirection); 1099 } 1100 1101 WritingDirection Editor::baseWritingDirectionForSelectionStart() const 1102 { 1103 WritingDirection result = LeftToRightWritingDirection; 1104 1105 Position pos = m_frame->selection()->selection().visibleStart().deepEquivalent(); 1106 Node* node = pos.deprecatedNode(); 1107 if (!node) 1108 return result; 1109 1110 RenderObject* renderer = node->renderer(); 1111 if (!renderer) 1112 return result; 1113 1114 if (!renderer->isBlockFlow()) { 1115 renderer = renderer->containingBlock(); 1116 if (!renderer) 1117 return result; 1118 } 1119 1120 RenderStyle* style = renderer->style(); 1121 if (!style) 1122 return result; 1123 1124 switch (style->direction()) { 1125 case LTR: 1126 return LeftToRightWritingDirection; 1127 case RTL: 1128 return RightToLeftWritingDirection; 1129 } 1130 1131 return result; 1132 } 1133 1134 void Editor::ignoreSpelling() 1135 { 1136 if (!client()) 1137 return; 1138 1139 RefPtr<Range> selectedRange = frame()->selection()->toNormalizedRange(); 1140 if (selectedRange) 1141 frame()->document()->markers()->removeMarkers(selectedRange.get(), DocumentMarker::Spelling); 1142 } 1143 1144 void Editor::advanceToNextMisspelling(bool startBeforeSelection) 1145 { 1146 // The basic approach is to search in two phases - from the selection end to the end of the doc, and 1147 // then we wrap and search from the doc start to (approximately) where we started. 1148 1149 // Start at the end of the selection, search to edge of document. Starting at the selection end makes 1150 // repeated "check spelling" commands work. 1151 VisibleSelection selection(frame()->selection()->selection()); 1152 RefPtr<Range> spellingSearchRange(rangeOfContents(frame()->document())); 1153 1154 bool startedWithSelection = false; 1155 if (selection.start().deprecatedNode()) { 1156 startedWithSelection = true; 1157 if (startBeforeSelection) { 1158 VisiblePosition start(selection.visibleStart()); 1159 // We match AppKit's rule: Start 1 character before the selection. 1160 VisiblePosition oneBeforeStart = start.previous(); 1161 setStart(spellingSearchRange.get(), oneBeforeStart.isNotNull() ? oneBeforeStart : start); 1162 } else 1163 setStart(spellingSearchRange.get(), selection.visibleEnd()); 1164 } 1165 1166 Position position = spellingSearchRange->startPosition(); 1167 if (!isEditablePosition(position)) { 1168 // This shouldn't happen in very often because the Spelling menu items aren't enabled unless the 1169 // selection is editable. 1170 // This can happen in Mail for a mix of non-editable and editable content (like Stationary), 1171 // when spell checking the whole document before sending the message. 1172 // In that case the document might not be editable, but there are editable pockets that need to be spell checked. 1173 1174 position = firstEditablePositionAfterPositionInRoot(position, frame()->document()->documentElement()).deepEquivalent(); 1175 if (position.isNull()) 1176 return; 1177 1178 Position rangeCompliantPosition = position.parentAnchoredEquivalent(); 1179 spellingSearchRange->setStart(rangeCompliantPosition.deprecatedNode(), rangeCompliantPosition.deprecatedEditingOffset(), IGNORE_EXCEPTION); 1180 startedWithSelection = false; // won't need to wrap 1181 } 1182 1183 // topNode defines the whole range we want to operate on 1184 Node* topNode = highestEditableRoot(position); 1185 // FIXME: lastOffsetForEditing() is wrong here if editingIgnoresContent(highestEditableRoot()) returns true (e.g. a <table>) 1186 spellingSearchRange->setEnd(topNode, lastOffsetForEditing(topNode), IGNORE_EXCEPTION); 1187 1188 // If spellingSearchRange starts in the middle of a word, advance to the next word so we start checking 1189 // at a word boundary. Going back by one char and then forward by a word does the trick. 1190 if (startedWithSelection) { 1191 VisiblePosition oneBeforeStart = startVisiblePosition(spellingSearchRange.get(), DOWNSTREAM).previous(); 1192 if (oneBeforeStart.isNotNull()) 1193 setStart(spellingSearchRange.get(), endOfWord(oneBeforeStart)); 1194 // else we were already at the start of the editable node 1195 } 1196 1197 if (spellingSearchRange->collapsed(IGNORE_EXCEPTION)) 1198 return; // nothing to search in 1199 1200 // Get the spell checker if it is available 1201 if (!client()) 1202 return; 1203 1204 // We go to the end of our first range instead of the start of it, just to be sure 1205 // we don't get foiled by any word boundary problems at the start. It means we might 1206 // do a tiny bit more searching. 1207 Node* searchEndNodeAfterWrap = spellingSearchRange->endContainer(); 1208 int searchEndOffsetAfterWrap = spellingSearchRange->endOffset(); 1209 1210 int misspellingOffset = 0; 1211 GrammarDetail grammarDetail; 1212 int grammarPhraseOffset = 0; 1213 RefPtr<Range> grammarSearchRange; 1214 String badGrammarPhrase; 1215 String misspelledWord; 1216 1217 bool isSpelling = true; 1218 int foundOffset = 0; 1219 String foundItem; 1220 RefPtr<Range> firstMisspellingRange; 1221 if (unifiedTextCheckerEnabled()) { 1222 grammarSearchRange = spellingSearchRange->cloneRange(IGNORE_EXCEPTION); 1223 foundItem = TextCheckingHelper(client(), spellingSearchRange).findFirstMisspellingOrBadGrammar(isGrammarCheckingEnabled(), isSpelling, foundOffset, grammarDetail); 1224 if (isSpelling) { 1225 misspelledWord = foundItem; 1226 misspellingOffset = foundOffset; 1227 } else { 1228 badGrammarPhrase = foundItem; 1229 grammarPhraseOffset = foundOffset; 1230 } 1231 } else { 1232 misspelledWord = TextCheckingHelper(client(), spellingSearchRange).findFirstMisspelling(misspellingOffset, false, firstMisspellingRange); 1233 grammarSearchRange = spellingSearchRange->cloneRange(IGNORE_EXCEPTION); 1234 if (!misspelledWord.isEmpty()) { 1235 // Stop looking at start of next misspelled word 1236 CharacterIterator chars(grammarSearchRange.get()); 1237 chars.advance(misspellingOffset); 1238 grammarSearchRange->setEnd(chars.range()->startContainer(), chars.range()->startOffset(), IGNORE_EXCEPTION); 1239 } 1240 1241 if (isGrammarCheckingEnabled()) 1242 badGrammarPhrase = TextCheckingHelper(client(), grammarSearchRange).findFirstBadGrammar(grammarDetail, grammarPhraseOffset, false); 1243 } 1244 1245 // If we found neither bad grammar nor a misspelled word, wrap and try again (but don't bother if we started at the beginning of the 1246 // block rather than at a selection). 1247 if (startedWithSelection && !misspelledWord && !badGrammarPhrase) { 1248 spellingSearchRange->setStart(topNode, 0, IGNORE_EXCEPTION); 1249 // going until the end of the very first chunk we tested is far enough 1250 spellingSearchRange->setEnd(searchEndNodeAfterWrap, searchEndOffsetAfterWrap, IGNORE_EXCEPTION); 1251 1252 if (unifiedTextCheckerEnabled()) { 1253 grammarSearchRange = spellingSearchRange->cloneRange(IGNORE_EXCEPTION); 1254 foundItem = TextCheckingHelper(client(), spellingSearchRange).findFirstMisspellingOrBadGrammar(isGrammarCheckingEnabled(), isSpelling, foundOffset, grammarDetail); 1255 if (isSpelling) { 1256 misspelledWord = foundItem; 1257 misspellingOffset = foundOffset; 1258 } else { 1259 badGrammarPhrase = foundItem; 1260 grammarPhraseOffset = foundOffset; 1261 } 1262 } else { 1263 misspelledWord = TextCheckingHelper(client(), spellingSearchRange).findFirstMisspelling(misspellingOffset, false, firstMisspellingRange); 1264 grammarSearchRange = spellingSearchRange->cloneRange(IGNORE_EXCEPTION); 1265 if (!misspelledWord.isEmpty()) { 1266 // Stop looking at start of next misspelled word 1267 CharacterIterator chars(grammarSearchRange.get()); 1268 chars.advance(misspellingOffset); 1269 grammarSearchRange->setEnd(chars.range()->startContainer(), chars.range()->startOffset(), IGNORE_EXCEPTION); 1270 } 1271 1272 if (isGrammarCheckingEnabled()) 1273 badGrammarPhrase = TextCheckingHelper(client(), grammarSearchRange).findFirstBadGrammar(grammarDetail, grammarPhraseOffset, false); 1274 } 1275 } 1276 1277 if (!badGrammarPhrase.isEmpty()) { 1278 // We found bad grammar. Since we only searched for bad grammar up to the first misspelled word, the bad grammar 1279 // takes precedence and we ignore any potential misspelled word. Select the grammar detail, update the spelling 1280 // panel, and store a marker so we draw the green squiggle later. 1281 1282 ASSERT(badGrammarPhrase.length() > 0); 1283 ASSERT(grammarDetail.location != -1 && grammarDetail.length > 0); 1284 1285 // FIXME 4859190: This gets confused with doubled punctuation at the end of a paragraph 1286 RefPtr<Range> badGrammarRange = TextIterator::subrange(grammarSearchRange.get(), grammarPhraseOffset + grammarDetail.location, grammarDetail.length); 1287 frame()->selection()->setSelection(VisibleSelection(badGrammarRange.get(), SEL_DEFAULT_AFFINITY)); 1288 frame()->selection()->revealSelection(); 1289 1290 frame()->document()->markers()->addMarker(badGrammarRange.get(), DocumentMarker::Grammar, grammarDetail.userDescription); 1291 } else if (!misspelledWord.isEmpty()) { 1292 // We found a misspelling, but not any earlier bad grammar. Select the misspelling, update the spelling panel, and store 1293 // a marker so we draw the red squiggle later. 1294 1295 RefPtr<Range> misspellingRange = TextIterator::subrange(spellingSearchRange.get(), misspellingOffset, misspelledWord.length()); 1296 frame()->selection()->setSelection(VisibleSelection(misspellingRange.get(), DOWNSTREAM)); 1297 frame()->selection()->revealSelection(); 1298 1299 client()->updateSpellingUIWithMisspelledWord(misspelledWord); 1300 frame()->document()->markers()->addMarker(misspellingRange.get(), DocumentMarker::Spelling); 1301 } 1302 } 1303 1304 String Editor::misspelledWordAtCaretOrRange(Node* clickedNode) const 1305 { 1306 if (!isContinuousSpellCheckingEnabled() || !clickedNode || !isSpellCheckingEnabledFor(clickedNode)) 1307 return String(); 1308 1309 VisibleSelection selection = m_frame->selection()->selection(); 1310 if (!selection.isContentEditable() || selection.isNone()) 1311 return String(); 1312 1313 VisibleSelection wordSelection(selection.base()); 1314 wordSelection.expandUsingGranularity(WordGranularity); 1315 RefPtr<Range> wordRange = wordSelection.toNormalizedRange(); 1316 1317 // In compliance with GTK+ applications, additionally allow to provide suggestions when the current 1318 // selection exactly match the word selection. 1319 if (selection.isRange() && !areRangesEqual(wordRange.get(), selection.toNormalizedRange().get())) 1320 return String(); 1321 1322 String word = wordRange->text(); 1323 if (word.isEmpty() || !client()) 1324 return String(); 1325 1326 int wordLength = word.length(); 1327 int misspellingLocation = -1; 1328 int misspellingLength = 0; 1329 textChecker()->checkSpellingOfString(word, &misspellingLocation, &misspellingLength); 1330 1331 return misspellingLength == wordLength ? word : String(); 1332 } 1333 1334 void Editor::showSpellingGuessPanel() 1335 { 1336 if (!client()) { 1337 LOG_ERROR("No NSSpellChecker"); 1338 return; 1339 } 1340 1341 if (client()->spellingUIIsShowing()) { 1342 client()->showSpellingUI(false); 1343 return; 1344 } 1345 1346 advanceToNextMisspelling(true); 1347 client()->showSpellingUI(true); 1348 } 1349 1350 void Editor::clearMisspellingsAndBadGrammar(const VisibleSelection &movingSelection) 1351 { 1352 RefPtr<Range> selectedRange = movingSelection.toNormalizedRange(); 1353 if (selectedRange) { 1354 frame()->document()->markers()->removeMarkers(selectedRange.get(), DocumentMarker::Spelling); 1355 frame()->document()->markers()->removeMarkers(selectedRange.get(), DocumentMarker::Grammar); 1356 } 1357 } 1358 1359 void Editor::markMisspellingsAndBadGrammar(const VisibleSelection &movingSelection) 1360 { 1361 markMisspellingsAndBadGrammar(movingSelection, isContinuousSpellCheckingEnabled() && isGrammarCheckingEnabled(), movingSelection); 1362 } 1363 1364 void Editor::markMisspellingsAfterTypingToWord(const VisiblePosition &wordStart, const VisibleSelection& selectionAfterTyping) 1365 { 1366 if (unifiedTextCheckerEnabled()) { 1367 TextCheckingTypeMask textCheckingOptions = 0; 1368 1369 if (isContinuousSpellCheckingEnabled()) 1370 textCheckingOptions |= TextCheckingTypeSpelling; 1371 1372 if (!(textCheckingOptions & TextCheckingTypeSpelling)) 1373 return; 1374 1375 if (isGrammarCheckingEnabled()) 1376 textCheckingOptions |= TextCheckingTypeGrammar; 1377 1378 VisibleSelection adjacentWords = VisibleSelection(startOfWord(wordStart, LeftWordIfOnBoundary), endOfWord(wordStart, RightWordIfOnBoundary)); 1379 if (textCheckingOptions & TextCheckingTypeGrammar) { 1380 VisibleSelection selectedSentence = VisibleSelection(startOfSentence(wordStart), endOfSentence(wordStart)); 1381 markAllMisspellingsAndBadGrammarInRanges(textCheckingOptions, adjacentWords.toNormalizedRange().get(), selectedSentence.toNormalizedRange().get()); 1382 } else 1383 markAllMisspellingsAndBadGrammarInRanges(textCheckingOptions, adjacentWords.toNormalizedRange().get(), adjacentWords.toNormalizedRange().get()); 1384 return; 1385 } 1386 1387 if (!isContinuousSpellCheckingEnabled()) 1388 return; 1389 1390 // Check spelling of one word 1391 RefPtr<Range> misspellingRange; 1392 markMisspellings(VisibleSelection(startOfWord(wordStart, LeftWordIfOnBoundary), endOfWord(wordStart, RightWordIfOnBoundary)), misspellingRange); 1393 1394 // Autocorrect the misspelled word. 1395 if (!misspellingRange) 1396 return; 1397 1398 // Get the misspelled word. 1399 const String misspelledWord = plainText(misspellingRange.get()); 1400 String autocorrectedString = textChecker()->getAutoCorrectSuggestionForMisspelledWord(misspelledWord); 1401 1402 // If autocorrected word is non empty, replace the misspelled word by this word. 1403 if (!autocorrectedString.isEmpty()) { 1404 VisibleSelection newSelection(misspellingRange.get(), DOWNSTREAM); 1405 if (newSelection != frame()->selection()->selection()) { 1406 if (!frame()->selection()->shouldChangeSelection(newSelection)) 1407 return; 1408 frame()->selection()->setSelection(newSelection); 1409 } 1410 1411 if (!frame()->editor()->shouldInsertText(autocorrectedString, misspellingRange.get(), EditorInsertActionTyped)) 1412 return; 1413 frame()->editor()->replaceSelectionWithText(autocorrectedString, false, false); 1414 1415 // Reset the charet one character further. 1416 frame()->selection()->moveTo(frame()->selection()->end()); 1417 frame()->selection()->modify(FrameSelection::AlterationMove, DirectionForward, CharacterGranularity); 1418 } 1419 1420 if (!isGrammarCheckingEnabled()) 1421 return; 1422 1423 // Check grammar of entire sentence 1424 markBadGrammar(VisibleSelection(startOfSentence(wordStart), endOfSentence(wordStart))); 1425 } 1426 1427 void Editor::markMisspellingsOrBadGrammar(const VisibleSelection& selection, bool checkSpelling, RefPtr<Range>& firstMisspellingRange) 1428 { 1429 // This function is called with a selection already expanded to word boundaries. 1430 // Might be nice to assert that here. 1431 1432 // This function is used only for as-you-type checking, so if that's off we do nothing. Note that 1433 // grammar checking can only be on if spell checking is also on. 1434 if (!isContinuousSpellCheckingEnabled()) 1435 return; 1436 1437 RefPtr<Range> searchRange(selection.toNormalizedRange()); 1438 if (!searchRange) 1439 return; 1440 1441 // If we're not in an editable node, bail. 1442 Node* editableNode = searchRange->startContainer(); 1443 if (!editableNode || !editableNode->rendererIsEditable()) 1444 return; 1445 1446 if (!isSpellCheckingEnabledFor(editableNode)) 1447 return; 1448 1449 // Get the spell checker if it is available 1450 if (!client()) 1451 return; 1452 1453 TextCheckingHelper checker(client(), searchRange); 1454 if (checkSpelling) 1455 checker.markAllMisspellings(firstMisspellingRange); 1456 else if (isGrammarCheckingEnabled()) 1457 checker.markAllBadGrammar(); 1458 } 1459 1460 bool Editor::isSpellCheckingEnabledFor(Node* node) const 1461 { 1462 if (!node) 1463 return false; 1464 const Element* focusedElement = node->isElementNode() ? toElement(node) : node->parentElement(); 1465 if (!focusedElement) 1466 return false; 1467 return focusedElement->isSpellCheckingEnabled(); 1468 } 1469 1470 bool Editor::isSpellCheckingEnabledInFocusedNode() const 1471 { 1472 return isSpellCheckingEnabledFor(m_frame->selection()->start().deprecatedNode()); 1473 } 1474 1475 void Editor::markMisspellings(const VisibleSelection& selection, RefPtr<Range>& firstMisspellingRange) 1476 { 1477 markMisspellingsOrBadGrammar(selection, true, firstMisspellingRange); 1478 } 1479 1480 void Editor::markBadGrammar(const VisibleSelection& selection) 1481 { 1482 RefPtr<Range> firstMisspellingRange; 1483 markMisspellingsOrBadGrammar(selection, false, firstMisspellingRange); 1484 } 1485 1486 void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingTypeMask textCheckingOptions, Range* spellingRange, Range* grammarRange) 1487 { 1488 ASSERT(m_frame); 1489 ASSERT(unifiedTextCheckerEnabled()); 1490 1491 bool shouldMarkGrammar = textCheckingOptions & TextCheckingTypeGrammar; 1492 1493 // This function is called with selections already expanded to word boundaries. 1494 if (!client() || !spellingRange || (shouldMarkGrammar && !grammarRange)) 1495 return; 1496 1497 // If we're not in an editable node, bail. 1498 Node* editableNode = spellingRange->startContainer(); 1499 if (!editableNode || !editableNode->rendererIsEditable()) 1500 return; 1501 1502 if (!isSpellCheckingEnabledFor(editableNode)) 1503 return; 1504 1505 Range* rangeToCheck = shouldMarkGrammar ? grammarRange : spellingRange; 1506 TextCheckingParagraph paragraphToCheck(rangeToCheck); 1507 if (paragraphToCheck.isRangeEmpty() || paragraphToCheck.isEmpty()) 1508 return; 1509 RefPtr<Range> paragraphRange = paragraphToCheck.paragraphRange(); 1510 1511 bool asynchronous = m_frame && m_frame->settings() && m_frame->settings()->asynchronousSpellCheckingEnabled(); 1512 1513 // In asynchronous mode, we intentionally check paragraph-wide sentence. 1514 RefPtr<SpellCheckRequest> request = SpellCheckRequest::create(resolveTextCheckingTypeMask(textCheckingOptions), TextCheckingProcessIncremental, asynchronous ? paragraphRange : rangeToCheck, paragraphRange); 1515 1516 if (asynchronous) { 1517 m_spellChecker->requestCheckingFor(request); 1518 return; 1519 } 1520 1521 Vector<TextCheckingResult> results; 1522 checkTextOfParagraph(textChecker(), paragraphToCheck.text(), resolveTextCheckingTypeMask(textCheckingOptions), results); 1523 markAndReplaceFor(request, results); 1524 } 1525 1526 void Editor::markAndReplaceFor(PassRefPtr<SpellCheckRequest> request, const Vector<TextCheckingResult>& results) 1527 { 1528 ASSERT(request); 1529 1530 TextCheckingTypeMask textCheckingOptions = request->data().mask(); 1531 TextCheckingParagraph paragraph(request->checkingRange(), request->paragraphRange()); 1532 1533 bool shouldMarkSpelling = textCheckingOptions & TextCheckingTypeSpelling; 1534 bool shouldMarkGrammar = textCheckingOptions & TextCheckingTypeGrammar; 1535 1536 // Expand the range to encompass entire paragraphs, since text checking needs that much context. 1537 int selectionOffset = 0; 1538 int ambiguousBoundaryOffset = -1; 1539 bool selectionChanged = false; 1540 bool restoreSelectionAfterChange = false; 1541 bool adjustSelectionForParagraphBoundaries = false; 1542 1543 if (shouldMarkSpelling) { 1544 if (m_frame->selection()->selectionType() == VisibleSelection::CaretSelection) { 1545 // Attempt to save the caret position so we can restore it later if needed 1546 Position caretPosition = m_frame->selection()->end(); 1547 selectionOffset = paragraph.offsetTo(caretPosition, ASSERT_NO_EXCEPTION); 1548 restoreSelectionAfterChange = true; 1549 if (selectionOffset > 0 && (static_cast<unsigned>(selectionOffset) > paragraph.text().length() || paragraph.textCharAt(selectionOffset - 1) == newlineCharacter)) 1550 adjustSelectionForParagraphBoundaries = true; 1551 if (selectionOffset > 0 && static_cast<unsigned>(selectionOffset) <= paragraph.text().length() && isAmbiguousBoundaryCharacter(paragraph.textCharAt(selectionOffset - 1))) 1552 ambiguousBoundaryOffset = selectionOffset - 1; 1553 } 1554 } 1555 1556 for (unsigned i = 0; i < results.size(); i++) { 1557 int spellingRangeEndOffset = paragraph.checkingEnd(); 1558 const TextCheckingResult* result = &results[i]; 1559 int resultLocation = result->location; 1560 int resultLength = result->length; 1561 bool resultEndsAtAmbiguousBoundary = ambiguousBoundaryOffset >= 0 && resultLocation + resultLength == ambiguousBoundaryOffset; 1562 1563 // Only mark misspelling if: 1564 // 1. Current text checking isn't done for autocorrection, in which case shouldMarkSpelling is false. 1565 // 2. Result falls within spellingRange. 1566 // 3. The word in question doesn't end at an ambiguous boundary. For instance, we would not mark 1567 // "wouldn'" as misspelled right after apostrophe is typed. 1568 if (shouldMarkSpelling && result->type == TextCheckingTypeSpelling && resultLocation >= paragraph.checkingStart() && resultLocation + resultLength <= spellingRangeEndOffset && !resultEndsAtAmbiguousBoundary) { 1569 ASSERT(resultLength > 0 && resultLocation >= 0); 1570 RefPtr<Range> misspellingRange = paragraph.subrange(resultLocation, resultLength); 1571 misspellingRange->startContainer()->document()->markers()->addMarker(misspellingRange.get(), DocumentMarker::Spelling, result->replacement, result->hash); 1572 } else if (shouldMarkGrammar && result->type == TextCheckingTypeGrammar && paragraph.checkingRangeCovers(resultLocation, resultLength)) { 1573 ASSERT(resultLength > 0 && resultLocation >= 0); 1574 for (unsigned j = 0; j < result->details.size(); j++) { 1575 const GrammarDetail* detail = &result->details[j]; 1576 ASSERT(detail->length > 0 && detail->location >= 0); 1577 if (paragraph.checkingRangeCovers(resultLocation + detail->location, detail->length)) { 1578 RefPtr<Range> badGrammarRange = paragraph.subrange(resultLocation + detail->location, detail->length); 1579 badGrammarRange->startContainer()->document()->markers()->addMarker(badGrammarRange.get(), DocumentMarker::Grammar, detail->userDescription, result->hash); 1580 } 1581 } 1582 } 1583 } 1584 1585 if (selectionChanged) { 1586 TextCheckingParagraph extendedParagraph(paragraph); 1587 // Restore the caret position if we have made any replacements 1588 extendedParagraph.expandRangeToNextEnd(); 1589 if (restoreSelectionAfterChange && selectionOffset >= 0 && selectionOffset <= extendedParagraph.rangeLength()) { 1590 RefPtr<Range> selectionRange = extendedParagraph.subrange(0, selectionOffset); 1591 m_frame->selection()->moveTo(selectionRange->endPosition(), DOWNSTREAM); 1592 if (adjustSelectionForParagraphBoundaries) 1593 m_frame->selection()->modify(FrameSelection::AlterationMove, DirectionForward, CharacterGranularity); 1594 } else { 1595 // If this fails for any reason, the fallback is to go one position beyond the last replacement 1596 m_frame->selection()->moveTo(m_frame->selection()->end()); 1597 m_frame->selection()->modify(FrameSelection::AlterationMove, DirectionForward, CharacterGranularity); 1598 } 1599 } 1600 } 1601 1602 void Editor::markMisspellingsAndBadGrammar(const VisibleSelection& spellingSelection, bool markGrammar, const VisibleSelection& grammarSelection) 1603 { 1604 if (unifiedTextCheckerEnabled()) { 1605 if (!isContinuousSpellCheckingEnabled()) 1606 return; 1607 1608 // markMisspellingsAndBadGrammar() is triggered by selection change, in which case we check spelling and grammar, but don't autocorrect misspellings. 1609 TextCheckingTypeMask textCheckingOptions = TextCheckingTypeSpelling; 1610 if (markGrammar && isGrammarCheckingEnabled()) 1611 textCheckingOptions |= TextCheckingTypeGrammar; 1612 markAllMisspellingsAndBadGrammarInRanges(textCheckingOptions, spellingSelection.toNormalizedRange().get(), grammarSelection.toNormalizedRange().get()); 1613 return; 1614 } 1615 1616 RefPtr<Range> firstMisspellingRange; 1617 markMisspellings(spellingSelection, firstMisspellingRange); 1618 if (markGrammar) 1619 markBadGrammar(grammarSelection); 1620 } 1621 1622 void Editor::updateMarkersForWordsAffectedByEditing(bool doNotRemoveIfSelectionAtWordBoundary) 1623 { 1624 if (!textChecker() || textChecker()->shouldEraseMarkersAfterChangeSelection(TextCheckingTypeSpelling)) 1625 return; 1626 1627 // We want to remove the markers from a word if an editing command will change the word. This can happen in one of 1628 // several scenarios: 1629 // 1. Insert in the middle of a word. 1630 // 2. Appending non whitespace at the beginning of word. 1631 // 3. Appending non whitespace at the end of word. 1632 // Note that, appending only whitespaces at the beginning or end of word won't change the word, so we don't need to 1633 // remove the markers on that word. 1634 // Of course, if current selection is a range, we potentially will edit two words that fall on the boundaries of 1635 // selection, and remove words between the selection boundaries. 1636 // 1637 VisiblePosition startOfSelection = frame()->selection()->selection().start(); 1638 VisiblePosition endOfSelection = frame()->selection()->selection().end(); 1639 if (startOfSelection.isNull()) 1640 return; 1641 // First word is the word that ends after or on the start of selection. 1642 VisiblePosition startOfFirstWord = startOfWord(startOfSelection, LeftWordIfOnBoundary); 1643 VisiblePosition endOfFirstWord = endOfWord(startOfSelection, LeftWordIfOnBoundary); 1644 // Last word is the word that begins before or on the end of selection 1645 VisiblePosition startOfLastWord = startOfWord(endOfSelection, RightWordIfOnBoundary); 1646 VisiblePosition endOfLastWord = endOfWord(endOfSelection, RightWordIfOnBoundary); 1647 1648 if (startOfFirstWord.isNull()) { 1649 startOfFirstWord = startOfWord(startOfSelection, RightWordIfOnBoundary); 1650 endOfFirstWord = endOfWord(startOfSelection, RightWordIfOnBoundary); 1651 } 1652 1653 if (endOfLastWord.isNull()) { 1654 startOfLastWord = startOfWord(endOfSelection, LeftWordIfOnBoundary); 1655 endOfLastWord = endOfWord(endOfSelection, LeftWordIfOnBoundary); 1656 } 1657 1658 // If doNotRemoveIfSelectionAtWordBoundary is true, and first word ends at the start of selection, 1659 // we choose next word as the first word. 1660 if (doNotRemoveIfSelectionAtWordBoundary && endOfFirstWord == startOfSelection) { 1661 startOfFirstWord = nextWordPosition(startOfFirstWord); 1662 endOfFirstWord = endOfWord(startOfFirstWord, RightWordIfOnBoundary); 1663 if (startOfFirstWord == endOfSelection) 1664 return; 1665 } 1666 1667 // If doNotRemoveIfSelectionAtWordBoundary is true, and last word begins at the end of selection, 1668 // we choose previous word as the last word. 1669 if (doNotRemoveIfSelectionAtWordBoundary && startOfLastWord == endOfSelection) { 1670 startOfLastWord = previousWordPosition(startOfLastWord); 1671 endOfLastWord = endOfWord(startOfLastWord, RightWordIfOnBoundary); 1672 if (endOfLastWord == startOfSelection) 1673 return; 1674 } 1675 1676 if (startOfFirstWord.isNull() || endOfFirstWord.isNull() || startOfLastWord.isNull() || endOfLastWord.isNull()) 1677 return; 1678 1679 // Now we remove markers on everything between startOfFirstWord and endOfLastWord. 1680 // However, if an autocorrection change a single word to multiple words, we want to remove correction mark from all the 1681 // resulted words even we only edit one of them. For example, assuming autocorrection changes "avantgarde" to "avant 1682 // garde", we will have CorrectionIndicator marker on both words and on the whitespace between them. If we then edit garde, 1683 // we would like to remove the marker from word "avant" and whitespace as well. So we need to get the continous range of 1684 // of marker that contains the word in question, and remove marker on that whole range. 1685 Document* document = m_frame->document(); 1686 RefPtr<Range> wordRange = Range::create(document, startOfFirstWord.deepEquivalent(), endOfLastWord.deepEquivalent()); 1687 1688 document->markers()->removeMarkers(wordRange.get(), DocumentMarker::Spelling | DocumentMarker::Grammar, DocumentMarkerController::RemovePartiallyOverlappingMarker); 1689 } 1690 1691 PassRefPtr<Range> Editor::rangeForPoint(const IntPoint& windowPoint) 1692 { 1693 Document* document = m_frame->documentAtPoint(windowPoint); 1694 if (!document) 1695 return 0; 1696 1697 Frame* frame = document->frame(); 1698 ASSERT(frame); 1699 FrameView* frameView = frame->view(); 1700 if (!frameView) 1701 return 0; 1702 IntPoint framePoint = frameView->windowToContents(windowPoint); 1703 VisibleSelection selection(frame->visiblePositionForPoint(framePoint)); 1704 1705 return selection.toNormalizedRange().get(); 1706 } 1707 1708 void Editor::revealSelectionAfterEditingOperation(const ScrollAlignment& alignment, RevealExtentOption revealExtentOption) 1709 { 1710 if (m_preventRevealSelection) 1711 return; 1712 1713 m_frame->selection()->revealSelection(alignment, revealExtentOption); 1714 } 1715 1716 bool Editor::setSelectionOffsets(int selectionStart, int selectionEnd) 1717 { 1718 Element* rootEditableElement = m_frame->selection()->rootEditableElement(); 1719 if (!rootEditableElement) 1720 return false; 1721 1722 RefPtr<Range> range = TextIterator::rangeFromLocationAndLength(rootEditableElement, selectionStart, selectionEnd - selectionStart); 1723 if (!range) 1724 return false; 1725 1726 return m_frame->selection()->setSelectedRange(range.get(), VP_DEFAULT_AFFINITY, true); 1727 } 1728 1729 void Editor::transpose() 1730 { 1731 if (!canEdit()) 1732 return; 1733 1734 VisibleSelection selection = m_frame->selection()->selection(); 1735 if (!selection.isCaret()) 1736 return; 1737 1738 // Make a selection that goes back one character and forward two characters. 1739 VisiblePosition caret = selection.visibleStart(); 1740 VisiblePosition next = isEndOfParagraph(caret) ? caret : caret.next(); 1741 VisiblePosition previous = next.previous(); 1742 if (next == previous) 1743 return; 1744 previous = previous.previous(); 1745 if (!inSameParagraph(next, previous)) 1746 return; 1747 RefPtr<Range> range = makeRange(previous, next); 1748 if (!range) 1749 return; 1750 VisibleSelection newSelection(range.get(), DOWNSTREAM); 1751 1752 // Transpose the two characters. 1753 String text = plainText(range.get()); 1754 if (text.length() != 2) 1755 return; 1756 String transposed = text.right(1) + text.left(1); 1757 1758 // Select the two characters. 1759 if (newSelection != m_frame->selection()->selection()) { 1760 if (!m_frame->selection()->shouldChangeSelection(newSelection)) 1761 return; 1762 m_frame->selection()->setSelection(newSelection); 1763 } 1764 1765 // Insert the transposed characters. 1766 if (!shouldInsertText(transposed, range.get(), EditorInsertActionTyped)) 1767 return; 1768 replaceSelectionWithText(transposed, false, false); 1769 } 1770 1771 void Editor::addToKillRing(Range* range, bool prepend) 1772 { 1773 if (m_shouldStartNewKillRingSequence) 1774 killRing()->startNewSequence(); 1775 1776 String text = plainText(range); 1777 if (prepend) 1778 killRing()->prepend(text); 1779 else 1780 killRing()->append(text); 1781 m_shouldStartNewKillRingSequence = false; 1782 } 1783 1784 void Editor::changeSelectionAfterCommand(const VisibleSelection& newSelection, FrameSelection::SetSelectionOptions options) 1785 { 1786 // If the new selection is orphaned, then don't update the selection. 1787 if (newSelection.start().isOrphan() || newSelection.end().isOrphan()) 1788 return; 1789 1790 // If there is no selection change, don't bother sending shouldChangeSelection, but still call setSelection, 1791 // because there is work that it must do in this situation. 1792 // The old selection can be invalid here and calling shouldChangeSelection can produce some strange calls. 1793 // See <rdar://problem/5729315> Some shouldChangeSelectedDOMRange contain Ranges for selections that are no longer valid 1794 bool selectionDidNotChangeDOMPosition = newSelection == m_frame->selection()->selection(); 1795 if (selectionDidNotChangeDOMPosition || m_frame->selection()->shouldChangeSelection(newSelection)) 1796 m_frame->selection()->setSelection(newSelection, options); 1797 1798 // Some editing operations change the selection visually without affecting its position within the DOM. 1799 // For example when you press return in the following (the caret is marked by ^): 1800 // <div contentEditable="true"><div>^Hello</div></div> 1801 // WebCore inserts <div><br></div> *before* the current block, which correctly moves the paragraph down but which doesn't 1802 // change the caret's DOM position (["hello", 0]). In these situations the above FrameSelection::setSelection call 1803 // does not call EditorClient::respondToChangedSelection(), which, on the Mac, sends selection change notifications and 1804 // starts a new kill ring sequence, but we want to do these things (matches AppKit). 1805 if (selectionDidNotChangeDOMPosition && client()) 1806 client()->respondToChangedSelection(m_frame); 1807 } 1808 1809 IntRect Editor::firstRectForRange(Range* range) const 1810 { 1811 LayoutUnit extraWidthToEndOfLine = 0; 1812 ASSERT(range->startContainer()); 1813 ASSERT(range->endContainer()); 1814 1815 IntRect startCaretRect = RenderedPosition(VisiblePosition(range->startPosition()).deepEquivalent(), DOWNSTREAM).absoluteRect(&extraWidthToEndOfLine); 1816 if (startCaretRect == LayoutRect()) 1817 return IntRect(); 1818 1819 IntRect endCaretRect = RenderedPosition(VisiblePosition(range->endPosition()).deepEquivalent(), UPSTREAM).absoluteRect(); 1820 if (endCaretRect == LayoutRect()) 1821 return IntRect(); 1822 1823 if (startCaretRect.y() == endCaretRect.y()) { 1824 // start and end are on the same line 1825 return IntRect(min(startCaretRect.x(), endCaretRect.x()), 1826 startCaretRect.y(), 1827 abs(endCaretRect.x() - startCaretRect.x()), 1828 max(startCaretRect.height(), endCaretRect.height())); 1829 } 1830 1831 // start and end aren't on the same line, so go from start to the end of its line 1832 return IntRect(startCaretRect.x(), 1833 startCaretRect.y(), 1834 startCaretRect.width() + extraWidthToEndOfLine, 1835 startCaretRect.height()); 1836 } 1837 1838 bool Editor::shouldChangeSelection(const VisibleSelection& oldSelection, const VisibleSelection& newSelection, EAffinity affinity, bool stillSelecting) const 1839 { 1840 return client() && client()->shouldChangeSelectedRange(oldSelection.toNormalizedRange().get(), newSelection.toNormalizedRange().get(), affinity, stillSelecting); 1841 } 1842 1843 void Editor::computeAndSetTypingStyle(StylePropertySet* style, EditAction editingAction) 1844 { 1845 if (!style || style->isEmpty()) { 1846 m_frame->selection()->clearTypingStyle(); 1847 return; 1848 } 1849 1850 // Calculate the current typing style. 1851 RefPtr<EditingStyle> typingStyle; 1852 if (m_frame->selection()->typingStyle()) { 1853 typingStyle = m_frame->selection()->typingStyle()->copy(); 1854 typingStyle->overrideWithStyle(style); 1855 } else 1856 typingStyle = EditingStyle::create(style); 1857 1858 typingStyle->prepareToApplyAt(m_frame->selection()->selection().visibleStart().deepEquivalent(), EditingStyle::PreserveWritingDirection); 1859 1860 // Handle block styles, substracting these from the typing style. 1861 RefPtr<EditingStyle> blockStyle = typingStyle->extractAndRemoveBlockProperties(); 1862 if (!blockStyle->isEmpty()) 1863 applyCommand(ApplyStyleCommand::create(m_frame->document(), blockStyle.get(), editingAction)); 1864 1865 // Set the remaining style as the typing style. 1866 m_frame->selection()->setTypingStyle(typingStyle); 1867 } 1868 1869 1870 void Editor::textFieldDidBeginEditing(Element* e) 1871 { 1872 if (isContinuousSpellCheckingEnabled()) { 1873 Element* element = toHTMLTextFormControlElement(e)->innerTextElement(); 1874 VisibleSelection selection = VisibleSelection::selectionFromContentsOfNode(element); 1875 markMisspellingsAndBadGrammar(selection); 1876 } 1877 } 1878 1879 void Editor::textFieldDidEndEditing(Element* e) 1880 { 1881 // Remove markers when deactivating a selection in an <input type="text"/>. 1882 // Prevent new ones from appearing too. 1883 m_spellChecker->cancelCheck(); 1884 HTMLTextFormControlElement* textFormControlElement = toHTMLTextFormControlElement(e); 1885 HTMLElement* innerText = textFormControlElement->innerTextElement(); 1886 DocumentMarker::MarkerTypes markerTypes(DocumentMarker::Spelling); 1887 if (isGrammarCheckingEnabled() || unifiedTextCheckerEnabled()) 1888 markerTypes.add(DocumentMarker::Grammar); 1889 for (Node* node = innerText; node; node = NodeTraversal::next(node, innerText)) { 1890 m_frame->document()->markers()->removeMarkers(node, markerTypes); 1891 } 1892 1893 if (client()) 1894 client()->textFieldDidEndEditing(e); 1895 } 1896 1897 void Editor::textDidChangeInTextField(Element* e) 1898 { 1899 if (client()) 1900 client()->textDidChangeInTextField(e); 1901 } 1902 1903 bool Editor::doTextFieldCommandFromEvent(Element* e, KeyboardEvent* ke) 1904 { 1905 if (client()) 1906 return client()->doTextFieldCommandFromEvent(e, ke); 1907 1908 return false; 1909 } 1910 1911 void Editor::applyEditingStyleToBodyElement() const 1912 { 1913 RefPtr<NodeList> list = m_frame->document()->getElementsByTagName("body"); 1914 unsigned len = list->length(); 1915 for (unsigned i = 0; i < len; i++) 1916 applyEditingStyleToElement(toElement(list->item(i))); 1917 } 1918 1919 void Editor::applyEditingStyleToElement(Element* element) const 1920 { 1921 if (!element) 1922 return; 1923 ASSERT(element->isStyledElement()); 1924 if (!element->isStyledElement()) 1925 return; 1926 1927 // Mutate using the CSSOM wrapper so we get the same event behavior as a script. 1928 CSSStyleDeclaration* style = element->style(); 1929 style->setPropertyInternal(CSSPropertyWordWrap, "break-word", false, IGNORE_EXCEPTION); 1930 style->setPropertyInternal(CSSPropertyWebkitLineBreak, "after-white-space", false, IGNORE_EXCEPTION); 1931 } 1932 1933 // Searches from the beginning of the document if nothing is selected. 1934 bool Editor::findString(const String& target, bool forward, bool caseFlag, bool wrapFlag, bool startInSelection) 1935 { 1936 FindOptions options = (forward ? 0 : Backwards) | (caseFlag ? 0 : CaseInsensitive) | (wrapFlag ? WrapAround : 0) | (startInSelection ? StartInSelection : 0); 1937 return findString(target, options); 1938 } 1939 1940 bool Editor::findString(const String& target, FindOptions options) 1941 { 1942 VisibleSelection selection = m_frame->selection()->selection(); 1943 1944 RefPtr<Range> resultRange = rangeOfString(target, selection.firstRange().get(), options); 1945 1946 if (!resultRange) 1947 return false; 1948 1949 m_frame->selection()->setSelection(VisibleSelection(resultRange.get(), DOWNSTREAM)); 1950 m_frame->selection()->revealSelection(); 1951 return true; 1952 } 1953 1954 PassRefPtr<Range> Editor::findStringAndScrollToVisible(const String& target, Range* previousMatch, FindOptions options) 1955 { 1956 RefPtr<Range> nextMatch = rangeOfString(target, previousMatch, options); 1957 if (!nextMatch) 1958 return 0; 1959 1960 nextMatch->firstNode()->renderer()->scrollRectToVisible(nextMatch->boundingBox(), 1961 ScrollAlignment::alignCenterIfNeeded, ScrollAlignment::alignCenterIfNeeded); 1962 1963 return nextMatch.release(); 1964 } 1965 1966 PassRefPtr<Range> Editor::rangeOfString(const String& target, Range* referenceRange, FindOptions options) 1967 { 1968 if (target.isEmpty()) 1969 return 0; 1970 1971 // Start from an edge of the reference range, if there's a reference range that's not in shadow content. Which edge 1972 // is used depends on whether we're searching forward or backward, and whether startInSelection is set. 1973 RefPtr<Range> searchRange(rangeOfContents(m_frame->document())); 1974 1975 bool forward = !(options & Backwards); 1976 bool startInReferenceRange = referenceRange && (options & StartInSelection); 1977 if (referenceRange) { 1978 if (forward) 1979 searchRange->setStart(startInReferenceRange ? referenceRange->startPosition() : referenceRange->endPosition()); 1980 else 1981 searchRange->setEnd(startInReferenceRange ? referenceRange->endPosition() : referenceRange->startPosition()); 1982 } 1983 1984 RefPtr<Node> shadowTreeRoot = referenceRange && referenceRange->startContainer() ? referenceRange->startContainer()->nonBoundaryShadowTreeRootNode() : 0; 1985 if (shadowTreeRoot) { 1986 if (forward) 1987 searchRange->setEnd(shadowTreeRoot.get(), shadowTreeRoot->childNodeCount()); 1988 else 1989 searchRange->setStart(shadowTreeRoot.get(), 0); 1990 } 1991 1992 RefPtr<Range> resultRange(findPlainText(searchRange.get(), target, options)); 1993 // If we started in the reference range and the found range exactly matches the reference range, find again. 1994 // Build a selection with the found range to remove collapsed whitespace. 1995 // Compare ranges instead of selection objects to ignore the way that the current selection was made. 1996 if (startInReferenceRange && areRangesEqual(VisibleSelection(resultRange.get()).toNormalizedRange().get(), referenceRange)) { 1997 searchRange = rangeOfContents(m_frame->document()); 1998 if (forward) 1999 searchRange->setStart(referenceRange->endPosition()); 2000 else 2001 searchRange->setEnd(referenceRange->startPosition()); 2002 2003 if (shadowTreeRoot) { 2004 if (forward) 2005 searchRange->setEnd(shadowTreeRoot.get(), shadowTreeRoot->childNodeCount()); 2006 else 2007 searchRange->setStart(shadowTreeRoot.get(), 0); 2008 } 2009 2010 resultRange = findPlainText(searchRange.get(), target, options); 2011 } 2012 2013 // If nothing was found in the shadow tree, search in main content following the shadow tree. 2014 if (resultRange->collapsed(ASSERT_NO_EXCEPTION) && shadowTreeRoot) { 2015 searchRange = rangeOfContents(m_frame->document()); 2016 if (forward) 2017 searchRange->setStartAfter(shadowTreeRoot->shadowHost()); 2018 else 2019 searchRange->setEndBefore(shadowTreeRoot->shadowHost()); 2020 2021 resultRange = findPlainText(searchRange.get(), target, options); 2022 } 2023 2024 // If we didn't find anything and we're wrapping, search again in the entire document (this will 2025 // redundantly re-search the area already searched in some cases). 2026 if (resultRange->collapsed(ASSERT_NO_EXCEPTION) && options & WrapAround) { 2027 searchRange = rangeOfContents(m_frame->document()); 2028 resultRange = findPlainText(searchRange.get(), target, options); 2029 // We used to return false here if we ended up with the same range that we started with 2030 // (e.g., the reference range was already the only instance of this text). But we decided that 2031 // this should be a success case instead, so we'll just fall through in that case. 2032 } 2033 2034 return resultRange->collapsed(ASSERT_NO_EXCEPTION) ? 0 : resultRange.release(); 2035 } 2036 2037 void Editor::setMarkedTextMatchesAreHighlighted(bool flag) 2038 { 2039 if (flag == m_areMarkedTextMatchesHighlighted) 2040 return; 2041 2042 m_areMarkedTextMatchesHighlighted = flag; 2043 m_frame->document()->markers()->repaintMarkers(DocumentMarker::TextMatch); 2044 } 2045 2046 void Editor::respondToChangedSelection(const VisibleSelection& oldSelection, FrameSelection::SetSelectionOptions options) 2047 { 2048 bool closeTyping = options & FrameSelection::CloseTyping; 2049 bool isContinuousSpellCheckingEnabled = this->isContinuousSpellCheckingEnabled(); 2050 bool isContinuousGrammarCheckingEnabled = isContinuousSpellCheckingEnabled && isGrammarCheckingEnabled(); 2051 if (isContinuousSpellCheckingEnabled) { 2052 VisibleSelection newAdjacentWords; 2053 VisibleSelection newSelectedSentence; 2054 bool caretBrowsing = m_frame->settings() && m_frame->settings()->caretBrowsingEnabled(); 2055 if (m_frame->selection()->selection().isContentEditable() || caretBrowsing) { 2056 VisiblePosition newStart(m_frame->selection()->selection().visibleStart()); 2057 newAdjacentWords = VisibleSelection(startOfWord(newStart, LeftWordIfOnBoundary), endOfWord(newStart, RightWordIfOnBoundary)); 2058 if (isContinuousGrammarCheckingEnabled) 2059 newSelectedSentence = VisibleSelection(startOfSentence(newStart), endOfSentence(newStart)); 2060 } 2061 2062 // Don't check spelling and grammar if the change of selection is triggered by spelling correction itself. 2063 bool shouldCheckSpellingAndGrammar = !(options & FrameSelection::SpellCorrectionTriggered); 2064 2065 // When typing we check spelling elsewhere, so don't redo it here. 2066 // If this is a change in selection resulting from a delete operation, 2067 // oldSelection may no longer be in the document. 2068 if (shouldCheckSpellingAndGrammar 2069 && closeTyping 2070 && oldSelection.isContentEditable() 2071 && oldSelection.start().deprecatedNode() 2072 && oldSelection.start().anchorNode()->inDocument() 2073 && !isSelectionInTextField(oldSelection)) { 2074 spellCheckOldSelection(oldSelection, newAdjacentWords, newSelectedSentence); 2075 } 2076 2077 if (!textChecker() || textChecker()->shouldEraseMarkersAfterChangeSelection(TextCheckingTypeSpelling)) { 2078 if (RefPtr<Range> wordRange = newAdjacentWords.toNormalizedRange()) 2079 m_frame->document()->markers()->removeMarkers(wordRange.get(), DocumentMarker::Spelling); 2080 } 2081 if (!textChecker() || textChecker()->shouldEraseMarkersAfterChangeSelection(TextCheckingTypeGrammar)) { 2082 if (RefPtr<Range> sentenceRange = newSelectedSentence.toNormalizedRange()) 2083 m_frame->document()->markers()->removeMarkers(sentenceRange.get(), DocumentMarker::Grammar); 2084 } 2085 } 2086 2087 // When continuous spell checking is off, existing markers disappear after the selection changes. 2088 if (!isContinuousSpellCheckingEnabled) 2089 m_frame->document()->markers()->removeMarkers(DocumentMarker::Spelling); 2090 if (!isContinuousGrammarCheckingEnabled) 2091 m_frame->document()->markers()->removeMarkers(DocumentMarker::Grammar); 2092 2093 m_frame->inputMethodController().cancelCompositionIfSelectionIsInvalid(); 2094 2095 notifyComponentsOnChangedSelection(oldSelection, options); 2096 } 2097 2098 void Editor::spellCheckAfterBlur() 2099 { 2100 if (!m_frame->selection()->selection().isContentEditable()) 2101 return; 2102 2103 if (isSelectionInTextField(m_frame->selection()->selection())) { 2104 // textFieldDidEndEditing() and textFieldDidBeginEditing() handle this. 2105 return; 2106 } 2107 2108 VisibleSelection empty; 2109 spellCheckOldSelection(m_frame->selection()->selection(), empty, empty); 2110 } 2111 2112 void Editor::spellCheckOldSelection(const VisibleSelection& oldSelection, const VisibleSelection& newAdjacentWords, const VisibleSelection& newSelectedSentence) 2113 { 2114 VisiblePosition oldStart(oldSelection.visibleStart()); 2115 VisibleSelection oldAdjacentWords = VisibleSelection(startOfWord(oldStart, LeftWordIfOnBoundary), endOfWord(oldStart, RightWordIfOnBoundary)); 2116 if (oldAdjacentWords != newAdjacentWords) { 2117 if (isContinuousSpellCheckingEnabled() && isGrammarCheckingEnabled()) { 2118 VisibleSelection selectedSentence = VisibleSelection(startOfSentence(oldStart), endOfSentence(oldStart)); 2119 markMisspellingsAndBadGrammar(oldAdjacentWords, selectedSentence != newSelectedSentence, selectedSentence); 2120 } else { 2121 markMisspellingsAndBadGrammar(oldAdjacentWords, false, oldAdjacentWords); 2122 } 2123 } 2124 } 2125 2126 static Node* findFirstMarkable(Node* node) 2127 { 2128 while (node) { 2129 if (!node->renderer()) 2130 return 0; 2131 if (node->renderer()->isText()) 2132 return node; 2133 if (node->renderer()->isTextControl()) 2134 node = toRenderTextControl(node->renderer())->textFormControlElement()->visiblePositionForIndex(1).deepEquivalent().deprecatedNode(); 2135 else if (node->firstChild()) 2136 node = node->firstChild(); 2137 else 2138 node = node->nextSibling(); 2139 } 2140 2141 return 0; 2142 } 2143 2144 bool Editor::selectionStartHasMarkerFor(DocumentMarker::MarkerType markerType, int from, int length) const 2145 { 2146 Node* node = findFirstMarkable(m_frame->selection()->start().deprecatedNode()); 2147 if (!node) 2148 return false; 2149 2150 unsigned int startOffset = static_cast<unsigned int>(from); 2151 unsigned int endOffset = static_cast<unsigned int>(from + length); 2152 Vector<DocumentMarker*> markers = m_frame->document()->markers()->markersFor(node); 2153 for (size_t i = 0; i < markers.size(); ++i) { 2154 DocumentMarker* marker = markers[i]; 2155 if (marker->startOffset() <= startOffset && endOffset <= marker->endOffset() && marker->type() == markerType) 2156 return true; 2157 } 2158 2159 return false; 2160 } 2161 2162 TextCheckingTypeMask Editor::resolveTextCheckingTypeMask(TextCheckingTypeMask textCheckingOptions) 2163 { 2164 bool shouldMarkSpelling = textCheckingOptions & TextCheckingTypeSpelling; 2165 bool shouldMarkGrammar = textCheckingOptions & TextCheckingTypeGrammar; 2166 2167 TextCheckingTypeMask checkingTypes = 0; 2168 if (shouldMarkSpelling) 2169 checkingTypes |= TextCheckingTypeSpelling; 2170 if (shouldMarkGrammar) 2171 checkingTypes |= TextCheckingTypeGrammar; 2172 2173 return checkingTypes; 2174 } 2175 2176 bool Editor::unifiedTextCheckerEnabled() const 2177 { 2178 return WebCore::unifiedTextCheckerEnabled(m_frame); 2179 } 2180 2181 void Editor::toggleOverwriteModeEnabled() 2182 { 2183 m_overwriteModeEnabled = !m_overwriteModeEnabled; 2184 frame()->selection()->setShouldShowBlockCursor(m_overwriteModeEnabled); 2185 }; 2186 2187 } // namespace WebCore 2188