Home | History | Annotate | Download | only in editing
      1 /*
      2  * Copyright (C) 2006, 2007, 2008 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 "Editor.h"
     29 
     30 #include "AXObjectCache.h"
     31 #include "ApplyStyleCommand.h"
     32 #include "CSSComputedStyleDeclaration.h"
     33 #include "CSSMutableStyleDeclaration.h"
     34 #include "CSSProperty.h"
     35 #include "CSSPropertyNames.h"
     36 #include "CSSStyleSelector.h"
     37 #include "CSSValueKeywords.h"
     38 #include "CachedResourceLoader.h"
     39 #include "ClipboardEvent.h"
     40 #include "CompositionEvent.h"
     41 #include "SpellingCorrectionController.h"
     42 #include "CreateLinkCommand.h"
     43 #include "DeleteButtonController.h"
     44 #include "DeleteSelectionCommand.h"
     45 #include "DocumentFragment.h"
     46 #include "DocumentMarkerController.h"
     47 #include "EditingText.h"
     48 #include "EditorClient.h"
     49 #include "EventHandler.h"
     50 #include "EventNames.h"
     51 #include "FocusController.h"
     52 #include "Frame.h"
     53 #include "FrameTree.h"
     54 #include "FrameView.h"
     55 #include "GraphicsContext.h"
     56 #include "HTMLFrameOwnerElement.h"
     57 #include "HTMLInputElement.h"
     58 #include "HTMLTextAreaElement.h"
     59 #include "HitTestResult.h"
     60 #include "IndentOutdentCommand.h"
     61 #include "InsertListCommand.h"
     62 #include "KeyboardEvent.h"
     63 #include "KillRing.h"
     64 #include "ModifySelectionListLevel.h"
     65 #include "NodeList.h"
     66 #include "Page.h"
     67 #include "Pasteboard.h"
     68 #include "TextCheckingHelper.h"
     69 #include "RemoveFormatCommand.h"
     70 #include "RenderBlock.h"
     71 #include "RenderPart.h"
     72 #include "RenderTextControl.h"
     73 #include "ReplaceSelectionCommand.h"
     74 #include "Settings.h"
     75 #include "Sound.h"
     76 #include "SpellChecker.h"
     77 #include "SpellingCorrectionCommand.h"
     78 #include "Text.h"
     79 #include "TextEvent.h"
     80 #include "TextIterator.h"
     81 #include "TypingCommand.h"
     82 #include "UserTypingGestureIndicator.h"
     83 #include "htmlediting.h"
     84 #include "markup.h"
     85 #include "visible_units.h"
     86 #include <wtf/UnusedParam.h>
     87 #include <wtf/unicode/CharacterNames.h>
     88 #include <wtf/unicode/Unicode.h>
     89 
     90 namespace WebCore {
     91 
     92 using namespace std;
     93 using namespace HTMLNames;
     94 using namespace WTF;
     95 using namespace Unicode;
     96 
     97 // When an event handler has moved the selection outside of a text control
     98 // we should use the target control's selection for this editing operation.
     99 VisibleSelection Editor::selectionForCommand(Event* event)
    100 {
    101     VisibleSelection selection = m_frame->selection()->selection();
    102     if (!event)
    103         return selection;
    104     // If the target is a text control, and the current selection is outside of its shadow tree,
    105     // then use the saved selection for that text control.
    106     Node* target = event->target()->toNode();
    107     Node* selectionStart = selection.start().deprecatedNode();
    108     if (target && (!selectionStart || target->shadowAncestorNode() != selectionStart->shadowAncestorNode())) {
    109         RefPtr<Range> range;
    110         if (target->hasTagName(inputTag) && static_cast<HTMLInputElement*>(target)->isTextField())
    111             range = static_cast<HTMLInputElement*>(target)->selection();
    112         else if (target->hasTagName(textareaTag))
    113             range = static_cast<HTMLTextAreaElement*>(target)->selection();
    114 
    115         if (range)
    116             return VisibleSelection(range.get());
    117     }
    118     return selection;
    119 }
    120 
    121 // Function considers Mac editing behavior a fallback when Page or Settings is not available.
    122 EditingBehavior Editor::behavior() const
    123 {
    124     if (!m_frame || !m_frame->settings())
    125         return EditingBehavior(EditingMacBehavior);
    126 
    127     return EditingBehavior(m_frame->settings()->editingBehaviorType());
    128 }
    129 
    130 EditorClient* Editor::client() const
    131 {
    132     if (Page* page = m_frame->page())
    133         return page->editorClient();
    134     return 0;
    135 }
    136 
    137 
    138 TextCheckerClient* Editor::textChecker() const
    139 {
    140     if (EditorClient* owner = client())
    141         return owner->textChecker();
    142     return 0;
    143 }
    144 
    145 void Editor::handleKeyboardEvent(KeyboardEvent* event)
    146 {
    147     if (EditorClient* c = client())
    148         c->handleKeyboardEvent(event);
    149 }
    150 
    151 void Editor::handleInputMethodKeydown(KeyboardEvent* event)
    152 {
    153     if (EditorClient* c = client())
    154         c->handleInputMethodKeydown(event);
    155 }
    156 
    157 bool Editor::handleTextEvent(TextEvent* event)
    158 {
    159     // Default event handling for Drag and Drop will be handled by DragController
    160     // so we leave the event for it.
    161     if (event->isDrop())
    162         return false;
    163 
    164     if (event->isPaste()) {
    165         if (event->pastingFragment())
    166             replaceSelectionWithFragment(event->pastingFragment(), false, event->shouldSmartReplace(), event->shouldMatchStyle());
    167         else
    168             replaceSelectionWithText(event->data(), false, event->shouldSmartReplace());
    169         return true;
    170     }
    171 
    172     String data = event->data();
    173     if (data == "\n") {
    174         if (event->isLineBreak())
    175             return insertLineBreak();
    176         return insertParagraphSeparator();
    177     }
    178 
    179     return insertTextWithoutSendingTextEvent(data, false, event);
    180 }
    181 
    182 bool Editor::canEdit() const
    183 {
    184     return m_frame->selection()->rootEditableElement();
    185 }
    186 
    187 bool Editor::canEditRichly() const
    188 {
    189     return m_frame->selection()->isContentRichlyEditable();
    190 }
    191 
    192 // WinIE uses onbeforecut and onbeforepaste to enables the cut and paste menu items.  They
    193 // also send onbeforecopy, apparently for symmetry, but it doesn't affect the menu items.
    194 // We need to use onbeforecopy as a real menu enabler because we allow elements that are not
    195 // normally selectable to implement copy/paste (like divs, or a document body).
    196 
    197 bool Editor::canDHTMLCut()
    198 {
    199     return !m_frame->selection()->isInPasswordField() && !dispatchCPPEvent(eventNames().beforecutEvent, ClipboardNumb);
    200 }
    201 
    202 bool Editor::canDHTMLCopy()
    203 {
    204     return !m_frame->selection()->isInPasswordField() && !dispatchCPPEvent(eventNames().beforecopyEvent, ClipboardNumb);
    205 }
    206 
    207 bool Editor::canDHTMLPaste()
    208 {
    209     return !dispatchCPPEvent(eventNames().beforepasteEvent, ClipboardNumb);
    210 }
    211 
    212 bool Editor::canCut() const
    213 {
    214     return canCopy() && canDelete();
    215 }
    216 
    217 static HTMLImageElement* imageElementFromImageDocument(Document* document)
    218 {
    219     if (!document)
    220         return 0;
    221     if (!document->isImageDocument())
    222         return 0;
    223 
    224     HTMLElement* body = document->body();
    225     if (!body)
    226         return 0;
    227 
    228     Node* node = body->firstChild();
    229     if (!node)
    230         return 0;
    231     if (!node->hasTagName(imgTag))
    232         return 0;
    233     return static_cast<HTMLImageElement*>(node);
    234 }
    235 
    236 bool Editor::canCopy() const
    237 {
    238     if (imageElementFromImageDocument(m_frame->document()))
    239         return true;
    240     SelectionController* selection = m_frame->selection();
    241     return selection->isRange() && !selection->isInPasswordField();
    242 }
    243 
    244 bool Editor::canPaste() const
    245 {
    246     return canEdit();
    247 }
    248 
    249 bool Editor::canDelete() const
    250 {
    251     SelectionController* selection = m_frame->selection();
    252     return selection->isRange() && selection->rootEditableElement();
    253 }
    254 
    255 bool Editor::canDeleteRange(Range* range) const
    256 {
    257     ExceptionCode ec = 0;
    258     Node* startContainer = range->startContainer(ec);
    259     Node* endContainer = range->endContainer(ec);
    260     if (!startContainer || !endContainer)
    261         return false;
    262 
    263     if (!startContainer->rendererIsEditable() || !endContainer->rendererIsEditable())
    264         return false;
    265 
    266     if (range->collapsed(ec)) {
    267         VisiblePosition start(Position(startContainer, range->startOffset(ec), Position::PositionIsOffsetInAnchor), DOWNSTREAM);
    268         VisiblePosition previous = start.previous();
    269         // FIXME: We sometimes allow deletions at the start of editable roots, like when the caret is in an empty list item.
    270         if (previous.isNull() || previous.deepEquivalent().deprecatedNode()->rootEditableElement() != startContainer->rootEditableElement())
    271             return false;
    272     }
    273     return true;
    274 }
    275 
    276 bool Editor::smartInsertDeleteEnabled()
    277 {
    278     return client() && client()->smartInsertDeleteEnabled();
    279 }
    280 
    281 bool Editor::canSmartCopyOrDelete()
    282 {
    283     return client() && client()->smartInsertDeleteEnabled() && m_frame->selection()->granularity() == WordGranularity;
    284 }
    285 
    286 bool Editor::isSelectTrailingWhitespaceEnabled()
    287 {
    288     return client() && client()->isSelectTrailingWhitespaceEnabled();
    289 }
    290 
    291 bool Editor::deleteWithDirection(SelectionDirection direction, TextGranularity granularity, bool killRing, bool isTypingAction)
    292 {
    293     if (!canEdit())
    294         return false;
    295 
    296     if (m_frame->selection()->isRange()) {
    297         if (isTypingAction) {
    298             TypingCommand::deleteKeyPressed(m_frame->document(), canSmartCopyOrDelete() ? TypingCommand::SmartDelete : 0, granularity);
    299             revealSelectionAfterEditingOperation();
    300         } else {
    301             if (killRing)
    302                 addToKillRing(selectedRange().get(), false);
    303             deleteSelectionWithSmartDelete(canSmartCopyOrDelete());
    304             // Implicitly calls revealSelectionAfterEditingOperation().
    305         }
    306     } else {
    307         TypingCommand::Options options = 0;
    308         if (canSmartCopyOrDelete())
    309             options |= TypingCommand::SmartDelete;
    310         if (killRing)
    311             options |= TypingCommand::KillRing;
    312         switch (direction) {
    313         case DirectionForward:
    314         case DirectionRight:
    315             TypingCommand::forwardDeleteKeyPressed(m_frame->document(), options, granularity);
    316             break;
    317         case DirectionBackward:
    318         case DirectionLeft:
    319             TypingCommand::deleteKeyPressed(m_frame->document(), options, granularity);
    320             break;
    321         }
    322         revealSelectionAfterEditingOperation();
    323     }
    324 
    325     // FIXME: We should to move this down into deleteKeyPressed.
    326     // clear the "start new kill ring sequence" setting, because it was set to true
    327     // when the selection was updated by deleting the range
    328     if (killRing)
    329         setStartNewKillRingSequence(false);
    330 
    331     return true;
    332 }
    333 
    334 void Editor::deleteSelectionWithSmartDelete(bool smartDelete)
    335 {
    336     if (m_frame->selection()->isNone())
    337         return;
    338 
    339     applyCommand(DeleteSelectionCommand::create(m_frame->document(), smartDelete));
    340 }
    341 
    342 void Editor::pasteAsPlainText(const String& pastingText, bool smartReplace)
    343 {
    344     Node* target = findEventTargetFromSelection();
    345     if (!target)
    346         return;
    347     ExceptionCode ec = 0;
    348     target->dispatchEvent(TextEvent::createForPlainTextPaste(m_frame->domWindow(), pastingText, smartReplace), ec);
    349 }
    350 
    351 void Editor::pasteAsFragment(PassRefPtr<DocumentFragment> pastingFragment, bool smartReplace, bool matchStyle)
    352 {
    353     Node* target = findEventTargetFromSelection();
    354     if (!target)
    355         return;
    356     ExceptionCode ec = 0;
    357     target->dispatchEvent(TextEvent::createForFragmentPaste(m_frame->domWindow(), pastingFragment, smartReplace, matchStyle), ec);
    358 }
    359 
    360 void Editor::pasteAsPlainTextBypassingDHTML()
    361 {
    362     pasteAsPlainTextWithPasteboard(Pasteboard::generalPasteboard());
    363 }
    364 
    365 void Editor::pasteAsPlainTextWithPasteboard(Pasteboard* pasteboard)
    366 {
    367     String text = pasteboard->plainText(m_frame);
    368     if (client() && client()->shouldInsertText(text, selectedRange().get(), EditorInsertActionPasted))
    369         pasteAsPlainText(text, canSmartReplaceWithPasteboard(pasteboard));
    370 }
    371 
    372 #if !PLATFORM(MAC)
    373 void Editor::pasteWithPasteboard(Pasteboard* pasteboard, bool allowPlainText)
    374 {
    375     RefPtr<Range> range = selectedRange();
    376     bool chosePlainText;
    377     RefPtr<DocumentFragment> fragment = pasteboard->documentFragment(m_frame, range, allowPlainText, chosePlainText);
    378     if (fragment && shouldInsertFragment(fragment, range, EditorInsertActionPasted))
    379         pasteAsFragment(fragment, canSmartReplaceWithPasteboard(pasteboard), chosePlainText);
    380 }
    381 #endif
    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() || !fragment)
    405         return;
    406 
    407     ReplaceSelectionCommand::CommandOptions options = ReplaceSelectionCommand::PreventNesting;
    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     Node* nodeToCheck = m_frame->selection()->rootEditableElement();
    418     if (m_spellChecker->canCheckAsynchronously(nodeToCheck))
    419         m_spellChecker->requestCheckingFor(textCheckingTypeMaskFor(MarkSpelling | MarkGrammar), nodeToCheck);
    420 }
    421 
    422 void Editor::replaceSelectionWithText(const String& text, bool selectReplacement, bool smartReplace)
    423 {
    424     replaceSelectionWithFragment(createFragmentFromText(selectedRange().get(), text), selectReplacement, smartReplace, true);
    425 }
    426 
    427 PassRefPtr<Range> Editor::selectedRange()
    428 {
    429     if (!m_frame)
    430         return 0;
    431     return m_frame->selection()->toNormalizedRange();
    432 }
    433 
    434 bool Editor::shouldDeleteRange(Range* range) const
    435 {
    436     ExceptionCode ec;
    437     if (!range || range->collapsed(ec))
    438         return false;
    439 
    440     if (!canDeleteRange(range))
    441         return false;
    442 
    443     return client() && client()->shouldDeleteRange(range);
    444 }
    445 
    446 bool Editor::tryDHTMLCopy()
    447 {
    448     if (m_frame->selection()->isInPasswordField())
    449         return false;
    450 
    451     if (canCopy())
    452         // Must be done before oncopy adds types and data to the pboard,
    453         // also done for security, as it erases data from the last copy/paste.
    454         Pasteboard::generalPasteboard()->clear();
    455 
    456     return !dispatchCPPEvent(eventNames().copyEvent, ClipboardWritable);
    457 }
    458 
    459 bool Editor::tryDHTMLCut()
    460 {
    461     if (m_frame->selection()->isInPasswordField())
    462         return false;
    463 
    464     if (canCut())
    465         // Must be done before oncut adds types and data to the pboard,
    466         // also done for security, as it erases data from the last copy/paste.
    467         Pasteboard::generalPasteboard()->clear();
    468 
    469     return !dispatchCPPEvent(eventNames().cutEvent, ClipboardWritable);
    470 }
    471 
    472 bool Editor::tryDHTMLPaste()
    473 {
    474     return !dispatchCPPEvent(eventNames().pasteEvent, ClipboardReadable);
    475 }
    476 
    477 void Editor::writeSelectionToPasteboard(Pasteboard* pasteboard)
    478 {
    479     pasteboard->writeSelection(selectedRange().get(), canSmartCopyOrDelete(), m_frame);
    480 }
    481 
    482 bool Editor::shouldInsertText(const String& text, Range* range, EditorInsertAction action) const
    483 {
    484     return client() && client()->shouldInsertText(text, range, action);
    485 }
    486 
    487 bool Editor::shouldShowDeleteInterface(HTMLElement* element) const
    488 {
    489     return client() && client()->shouldShowDeleteInterface(element);
    490 }
    491 
    492 void Editor::respondToChangedSelection(const VisibleSelection& oldSelection)
    493 {
    494     if (client())
    495         client()->respondToChangedSelection();
    496     m_deleteButtonController->respondToChangedSelection(oldSelection);
    497     m_spellingCorrector->respondToChangedSelection(oldSelection);
    498 }
    499 
    500 void Editor::respondToChangedContents(const VisibleSelection& endingSelection)
    501 {
    502     if (AXObjectCache::accessibilityEnabled()) {
    503         Node* node = endingSelection.start().deprecatedNode();
    504         if (node)
    505             m_frame->document()->axObjectCache()->postNotification(node->renderer(), AXObjectCache::AXValueChanged, false);
    506     }
    507 
    508     updateMarkersForWordsAffectedByEditing(true);
    509 
    510     if (client())
    511         client()->respondToChangedContents();
    512 }
    513 
    514 const SimpleFontData* Editor::fontForSelection(bool& hasMultipleFonts) const
    515 {
    516 #if !PLATFORM(QT)
    517     hasMultipleFonts = false;
    518 
    519     if (!m_frame->selection()->isRange()) {
    520         Node* nodeToRemove;
    521         RenderStyle* style = styleForSelectionStart(nodeToRemove); // sets nodeToRemove
    522 
    523         const SimpleFontData* result = 0;
    524         if (style)
    525             result = style->font().primaryFont();
    526 
    527         if (nodeToRemove) {
    528             ExceptionCode ec;
    529             nodeToRemove->remove(ec);
    530             ASSERT(!ec);
    531         }
    532 
    533         return result;
    534     }
    535 
    536     const SimpleFontData* font = 0;
    537 
    538     RefPtr<Range> range = m_frame->selection()->toNormalizedRange();
    539     Node* startNode = range->editingStartPosition().deprecatedNode();
    540     if (startNode) {
    541         Node* pastEnd = range->pastLastNode();
    542         // In the loop below, n should eventually match pastEnd and not become nil, but we've seen at least one
    543         // unreproducible case where this didn't happen, so check for nil also.
    544         for (Node* n = startNode; n && n != pastEnd; n = n->traverseNextNode()) {
    545             RenderObject* renderer = n->renderer();
    546             if (!renderer)
    547                 continue;
    548             // FIXME: Are there any node types that have renderers, but that we should be skipping?
    549             const SimpleFontData* f = renderer->style()->font().primaryFont();
    550             if (!font)
    551                 font = f;
    552             else if (font != f) {
    553                 hasMultipleFonts = true;
    554                 break;
    555             }
    556         }
    557     }
    558 
    559     return font;
    560 #else
    561     return 0;
    562 #endif
    563 }
    564 
    565 WritingDirection Editor::textDirectionForSelection(bool& hasNestedOrMultipleEmbeddings) const
    566 {
    567     hasNestedOrMultipleEmbeddings = true;
    568 
    569     if (m_frame->selection()->isNone())
    570         return NaturalWritingDirection;
    571 
    572     Position position = m_frame->selection()->selection().start().downstream();
    573 
    574     Node* node = position.deprecatedNode();
    575     if (!node)
    576         return NaturalWritingDirection;
    577 
    578     Position end;
    579     if (m_frame->selection()->isRange()) {
    580         end = m_frame->selection()->selection().end().upstream();
    581 
    582         Node* pastLast = Range::create(m_frame->document(), position.parentAnchoredEquivalent(), end.parentAnchoredEquivalent())->pastLastNode();
    583         for (Node* n = node; n && n != pastLast; n = n->traverseNextNode()) {
    584             if (!n->isStyledElement())
    585                 continue;
    586 
    587             RefPtr<CSSComputedStyleDeclaration> style = computedStyle(n);
    588             RefPtr<CSSValue> unicodeBidi = style->getPropertyCSSValue(CSSPropertyUnicodeBidi);
    589             if (!unicodeBidi || !unicodeBidi->isPrimitiveValue())
    590                 continue;
    591 
    592             int unicodeBidiValue = static_cast<CSSPrimitiveValue*>(unicodeBidi.get())->getIdent();
    593             if (unicodeBidiValue == CSSValueEmbed || unicodeBidiValue == CSSValueBidiOverride)
    594                 return NaturalWritingDirection;
    595         }
    596     }
    597 
    598     if (m_frame->selection()->isCaret()) {
    599         RefPtr<EditingStyle> typingStyle = m_frame->selection()->typingStyle();
    600         WritingDirection direction;
    601         if (typingStyle && typingStyle->textDirection(direction)) {
    602             hasNestedOrMultipleEmbeddings = false;
    603             return direction;
    604         }
    605         node = m_frame->selection()->selection().visibleStart().deepEquivalent().deprecatedNode();
    606     }
    607 
    608     // The selection is either a caret with no typing attributes or a range in which no embedding is added, so just use the start position
    609     // to decide.
    610     Node* block = enclosingBlock(node);
    611     WritingDirection foundDirection = NaturalWritingDirection;
    612 
    613     for (; node != block; node = node->parentNode()) {
    614         if (!node->isStyledElement())
    615             continue;
    616 
    617         RefPtr<CSSComputedStyleDeclaration> style = computedStyle(node);
    618         RefPtr<CSSValue> unicodeBidi = style->getPropertyCSSValue(CSSPropertyUnicodeBidi);
    619         if (!unicodeBidi || !unicodeBidi->isPrimitiveValue())
    620             continue;
    621 
    622         int unicodeBidiValue = static_cast<CSSPrimitiveValue*>(unicodeBidi.get())->getIdent();
    623         if (unicodeBidiValue == CSSValueNormal)
    624             continue;
    625 
    626         if (unicodeBidiValue == CSSValueBidiOverride)
    627             return NaturalWritingDirection;
    628 
    629         ASSERT(unicodeBidiValue == CSSValueEmbed);
    630         RefPtr<CSSValue> direction = style->getPropertyCSSValue(CSSPropertyDirection);
    631         if (!direction || !direction->isPrimitiveValue())
    632             continue;
    633 
    634         int directionValue = static_cast<CSSPrimitiveValue*>(direction.get())->getIdent();
    635         if (directionValue != CSSValueLtr && directionValue != CSSValueRtl)
    636             continue;
    637 
    638         if (foundDirection != NaturalWritingDirection)
    639             return NaturalWritingDirection;
    640 
    641         // In the range case, make sure that the embedding element persists until the end of the range.
    642         if (m_frame->selection()->isRange() && !end.deprecatedNode()->isDescendantOf(node))
    643             return NaturalWritingDirection;
    644 
    645         foundDirection = directionValue == CSSValueLtr ? LeftToRightWritingDirection : RightToLeftWritingDirection;
    646     }
    647     hasNestedOrMultipleEmbeddings = false;
    648     return foundDirection;
    649 }
    650 
    651 bool Editor::hasBidiSelection() const
    652 {
    653     if (m_frame->selection()->isNone())
    654         return false;
    655 
    656     Node* startNode;
    657     if (m_frame->selection()->isRange()) {
    658         startNode = m_frame->selection()->selection().start().downstream().deprecatedNode();
    659         Node* endNode = m_frame->selection()->selection().end().upstream().deprecatedNode();
    660         if (enclosingBlock(startNode) != enclosingBlock(endNode))
    661             return false;
    662     } else
    663         startNode = m_frame->selection()->selection().visibleStart().deepEquivalent().deprecatedNode();
    664 
    665     RenderObject* renderer = startNode->renderer();
    666     while (renderer && !renderer->isRenderBlock())
    667         renderer = renderer->parent();
    668 
    669     if (!renderer)
    670         return false;
    671 
    672     RenderStyle* style = renderer->style();
    673     if (!style->isLeftToRightDirection())
    674         return true;
    675 
    676     return toRenderBlock(renderer)->containsNonZeroBidiLevel();
    677 }
    678 
    679 TriState Editor::selectionUnorderedListState() const
    680 {
    681     if (m_frame->selection()->isCaret()) {
    682         if (enclosingNodeWithTag(m_frame->selection()->selection().start(), ulTag))
    683             return TrueTriState;
    684     } else if (m_frame->selection()->isRange()) {
    685         Node* startNode = enclosingNodeWithTag(m_frame->selection()->selection().start(), ulTag);
    686         Node* endNode = enclosingNodeWithTag(m_frame->selection()->selection().end(), ulTag);
    687         if (startNode && endNode && startNode == endNode)
    688             return TrueTriState;
    689     }
    690 
    691     return FalseTriState;
    692 }
    693 
    694 TriState Editor::selectionOrderedListState() const
    695 {
    696     if (m_frame->selection()->isCaret()) {
    697         if (enclosingNodeWithTag(m_frame->selection()->selection().start(), olTag))
    698             return TrueTriState;
    699     } else if (m_frame->selection()->isRange()) {
    700         Node* startNode = enclosingNodeWithTag(m_frame->selection()->selection().start(), olTag);
    701         Node* endNode = enclosingNodeWithTag(m_frame->selection()->selection().end(), olTag);
    702         if (startNode && endNode && startNode == endNode)
    703             return TrueTriState;
    704     }
    705 
    706     return FalseTriState;
    707 }
    708 
    709 PassRefPtr<Node> Editor::insertOrderedList()
    710 {
    711     if (!canEditRichly())
    712         return 0;
    713 
    714     RefPtr<Node> newList = InsertListCommand::insertList(m_frame->document(), InsertListCommand::OrderedList);
    715     revealSelectionAfterEditingOperation();
    716     return newList;
    717 }
    718 
    719 PassRefPtr<Node> Editor::insertUnorderedList()
    720 {
    721     if (!canEditRichly())
    722         return 0;
    723 
    724     RefPtr<Node> newList = InsertListCommand::insertList(m_frame->document(), InsertListCommand::UnorderedList);
    725     revealSelectionAfterEditingOperation();
    726     return newList;
    727 }
    728 
    729 bool Editor::canIncreaseSelectionListLevel()
    730 {
    731     return canEditRichly() && IncreaseSelectionListLevelCommand::canIncreaseSelectionListLevel(m_frame->document());
    732 }
    733 
    734 bool Editor::canDecreaseSelectionListLevel()
    735 {
    736     return canEditRichly() && DecreaseSelectionListLevelCommand::canDecreaseSelectionListLevel(m_frame->document());
    737 }
    738 
    739 PassRefPtr<Node> Editor::increaseSelectionListLevel()
    740 {
    741     if (!canEditRichly() || m_frame->selection()->isNone())
    742         return 0;
    743 
    744     RefPtr<Node> newList = IncreaseSelectionListLevelCommand::increaseSelectionListLevel(m_frame->document());
    745     revealSelectionAfterEditingOperation();
    746     return newList;
    747 }
    748 
    749 PassRefPtr<Node> Editor::increaseSelectionListLevelOrdered()
    750 {
    751     if (!canEditRichly() || m_frame->selection()->isNone())
    752         return 0;
    753 
    754     RefPtr<Node> newList = IncreaseSelectionListLevelCommand::increaseSelectionListLevelOrdered(m_frame->document());
    755     revealSelectionAfterEditingOperation();
    756     return newList.release();
    757 }
    758 
    759 PassRefPtr<Node> Editor::increaseSelectionListLevelUnordered()
    760 {
    761     if (!canEditRichly() || m_frame->selection()->isNone())
    762         return 0;
    763 
    764     RefPtr<Node> newList = IncreaseSelectionListLevelCommand::increaseSelectionListLevelUnordered(m_frame->document());
    765     revealSelectionAfterEditingOperation();
    766     return newList.release();
    767 }
    768 
    769 void Editor::decreaseSelectionListLevel()
    770 {
    771     if (!canEditRichly() || m_frame->selection()->isNone())
    772         return;
    773 
    774     DecreaseSelectionListLevelCommand::decreaseSelectionListLevel(m_frame->document());
    775     revealSelectionAfterEditingOperation();
    776 }
    777 
    778 void Editor::removeFormattingAndStyle()
    779 {
    780     applyCommand(RemoveFormatCommand::create(m_frame->document()));
    781 }
    782 
    783 void Editor::clearLastEditCommand()
    784 {
    785     m_lastEditCommand.clear();
    786 }
    787 
    788 // Returns whether caller should continue with "the default processing", which is the same as
    789 // the event handler NOT setting the return value to false
    790 bool Editor::dispatchCPPEvent(const AtomicString &eventType, ClipboardAccessPolicy policy)
    791 {
    792     Node* target = findEventTargetFromSelection();
    793     if (!target)
    794         return true;
    795 
    796     RefPtr<Clipboard> clipboard = newGeneralClipboard(policy, m_frame);
    797 
    798     ExceptionCode ec = 0;
    799     RefPtr<Event> evt = ClipboardEvent::create(eventType, true, true, clipboard);
    800     target->dispatchEvent(evt, ec);
    801     bool noDefaultProcessing = evt->defaultPrevented();
    802 
    803     // invalidate clipboard here for security
    804     clipboard->setAccessPolicy(ClipboardNumb);
    805 
    806     return !noDefaultProcessing;
    807 }
    808 
    809 Node* Editor::findEventTargetFrom(const VisibleSelection& selection) const
    810 {
    811     Node* target = selection.start().element();
    812     if (!target)
    813         target = m_frame->document()->body();
    814     if (!target)
    815         return 0;
    816     return target->shadowAncestorNode();
    817 
    818 }
    819 
    820 Node* Editor::findEventTargetFromSelection() const
    821 {
    822     return findEventTargetFrom(m_frame->selection()->selection());
    823 }
    824 
    825 void Editor::applyStyle(CSSStyleDeclaration* style, EditAction editingAction)
    826 {
    827     switch (m_frame->selection()->selectionType()) {
    828     case VisibleSelection::NoSelection:
    829         // do nothing
    830         break;
    831     case VisibleSelection::CaretSelection:
    832         computeAndSetTypingStyle(style, editingAction);
    833         break;
    834     case VisibleSelection::RangeSelection:
    835         if (style)
    836             applyCommand(ApplyStyleCommand::create(m_frame->document(), EditingStyle::create(style).get(), editingAction));
    837         break;
    838     }
    839 }
    840 
    841 bool Editor::shouldApplyStyle(CSSStyleDeclaration* style, Range* range)
    842 {
    843     return client()->shouldApplyStyle(style, range);
    844 }
    845 
    846 void Editor::applyParagraphStyle(CSSStyleDeclaration* style, EditAction editingAction)
    847 {
    848     switch (m_frame->selection()->selectionType()) {
    849     case VisibleSelection::NoSelection:
    850         // do nothing
    851         break;
    852     case VisibleSelection::CaretSelection:
    853     case VisibleSelection::RangeSelection:
    854         if (style)
    855             applyCommand(ApplyStyleCommand::create(m_frame->document(), EditingStyle::create(style).get(), editingAction, ApplyStyleCommand::ForceBlockProperties));
    856         break;
    857     }
    858 }
    859 
    860 void Editor::applyStyleToSelection(CSSStyleDeclaration* style, EditAction editingAction)
    861 {
    862     if (!style || !style->length() || !canEditRichly())
    863         return;
    864 
    865     if (client() && client()->shouldApplyStyle(style, m_frame->selection()->toNormalizedRange().get()))
    866         applyStyle(style, editingAction);
    867 }
    868 
    869 void Editor::applyParagraphStyleToSelection(CSSStyleDeclaration* style, EditAction editingAction)
    870 {
    871     if (!style || !style->length() || !canEditRichly())
    872         return;
    873 
    874     if (client() && client()->shouldApplyStyle(style, m_frame->selection()->toNormalizedRange().get()))
    875         applyParagraphStyle(style, editingAction);
    876 }
    877 
    878 bool Editor::selectionStartHasStyle(int propertyID, const String& value) const
    879 {
    880     RefPtr<EditingStyle> style = EditingStyle::create(propertyID, value);
    881     RefPtr<EditingStyle> selectionStyle = selectionStartStyle();
    882     if (!selectionStyle || !selectionStyle->style())
    883         return false;
    884     return style->triStateOfStyle(selectionStyle->style()) == TrueTriState;
    885 }
    886 
    887 TriState Editor::selectionHasStyle(int propertyID, const String& value) const
    888 {
    889     RefPtr<EditingStyle> style = EditingStyle::create(propertyID, value);
    890     if (!m_frame->selection()->isCaretOrRange())
    891         return FalseTriState;
    892 
    893     if (m_frame->selection()->isCaret()) {
    894         RefPtr<EditingStyle> selectionStyle = selectionStartStyle();
    895         if (!selectionStyle || !selectionStyle->style())
    896             return FalseTriState;
    897         return style->triStateOfStyle(selectionStyle->style());
    898     }
    899 
    900     TriState state = FalseTriState;
    901     for (Node* node = m_frame->selection()->start().deprecatedNode(); node; node = node->traverseNextNode()) {
    902         RefPtr<CSSComputedStyleDeclaration> nodeStyle = computedStyle(node);
    903         if (nodeStyle) {
    904             TriState nodeState = style->triStateOfStyle(nodeStyle.get(), node->isTextNode() ? EditingStyle::DoNotIgnoreTextOnlyProperties : EditingStyle::IgnoreTextOnlyProperties);
    905             if (node == m_frame->selection()->start().deprecatedNode())
    906                 state = nodeState;
    907             else if (state != nodeState && node->isTextNode()) {
    908                 state = MixedTriState;
    909                 break;
    910             }
    911         }
    912         if (node == m_frame->selection()->end().deprecatedNode())
    913             break;
    914     }
    915 
    916     return state;
    917 }
    918 
    919 static bool hasTransparentBackgroundColor(CSSStyleDeclaration* style)
    920 {
    921     RefPtr<CSSValue> cssValue = style->getPropertyCSSValue(CSSPropertyBackgroundColor);
    922     if (!cssValue)
    923         return true;
    924 
    925     if (!cssValue->isPrimitiveValue())
    926         return false;
    927     CSSPrimitiveValue* value = static_cast<CSSPrimitiveValue*>(cssValue.get());
    928 
    929     if (value->primitiveType() == CSSPrimitiveValue::CSS_RGBCOLOR)
    930         return !alphaChannel(value->getRGBA32Value());
    931 
    932     return value->getIdent() == CSSValueTransparent;
    933 }
    934 
    935 String Editor::selectionStartCSSPropertyValue(int propertyID)
    936 {
    937     RefPtr<EditingStyle> selectionStyle = selectionStartStyle();
    938     if (!selectionStyle || !selectionStyle->style())
    939         return String();
    940 
    941     String value = selectionStyle->style()->getPropertyValue(propertyID);
    942 
    943     // If background color is transparent, traverse parent nodes until we hit a different value or document root
    944     // Also, if the selection is a range, ignore the background color at the start of selection,
    945     // and find the background color of the common ancestor.
    946     if (propertyID == CSSPropertyBackgroundColor && (m_frame->selection()->isRange() || hasTransparentBackgroundColor(selectionStyle->style()))) {
    947         RefPtr<Range> range(m_frame->selection()->toNormalizedRange());
    948         ExceptionCode ec = 0;
    949         for (Node* ancestor = range->commonAncestorContainer(ec); ancestor; ancestor = ancestor->parentNode()) {
    950             RefPtr<CSSComputedStyleDeclaration> ancestorStyle = computedStyle(ancestor);
    951             if (!hasTransparentBackgroundColor(ancestorStyle.get()))
    952                 return ancestorStyle->getPropertyValue(CSSPropertyBackgroundColor);
    953         }
    954     }
    955 
    956     if (propertyID == CSSPropertyFontSize) {
    957         RefPtr<CSSValue> cssValue = selectionStyle->style()->getPropertyCSSValue(CSSPropertyFontSize);
    958         if (cssValue->isPrimitiveValue()) {
    959             value = String::number(legacyFontSizeFromCSSValue(m_frame->document(), static_cast<CSSPrimitiveValue*>(cssValue.get()),
    960                 selectionStyle->shouldUseFixedDefaultFontSize(), AlwaysUseLegacyFontSize));
    961         }
    962     }
    963 
    964     return value;
    965 }
    966 
    967 void Editor::indent()
    968 {
    969     applyCommand(IndentOutdentCommand::create(m_frame->document(), IndentOutdentCommand::Indent));
    970 }
    971 
    972 void Editor::outdent()
    973 {
    974     applyCommand(IndentOutdentCommand::create(m_frame->document(), IndentOutdentCommand::Outdent));
    975 }
    976 
    977 static void dispatchEditableContentChangedEvents(const EditCommand& command)
    978 {
    979     Element* startRoot = command.startingRootEditableElement();
    980     Element* endRoot = command.endingRootEditableElement();
    981     ExceptionCode ec;
    982     if (startRoot)
    983         startRoot->dispatchEvent(Event::create(eventNames().webkitEditableContentChangedEvent, false, false), ec);
    984     if (endRoot && endRoot != startRoot)
    985         endRoot->dispatchEvent(Event::create(eventNames().webkitEditableContentChangedEvent, false, false), ec);
    986 }
    987 
    988 void Editor::appliedEditing(PassRefPtr<EditCommand> cmd)
    989 {
    990     m_frame->document()->updateLayout();
    991 
    992     dispatchEditableContentChangedEvents(*cmd);
    993     VisibleSelection newSelection(cmd->endingSelection());
    994 
    995     m_spellingCorrector->respondToAppliedEditing(cmd.get());
    996 
    997     // Don't clear the typing style with this selection change.  We do those things elsewhere if necessary.
    998     changeSelectionAfterCommand(newSelection, false, false);
    999 
   1000     if (!cmd->preservesTypingStyle())
   1001         m_frame->selection()->clearTypingStyle();
   1002 
   1003     // Command will be equal to last edit command only in the case of typing
   1004     if (m_lastEditCommand.get() == cmd)
   1005         ASSERT(cmd->isTypingCommand());
   1006     else {
   1007         // Only register a new undo command if the command passed in is
   1008         // different from the last command
   1009         m_lastEditCommand = cmd;
   1010         if (client())
   1011             client()->registerCommandForUndo(m_lastEditCommand);
   1012     }
   1013     respondToChangedContents(newSelection);
   1014 }
   1015 
   1016 void Editor::unappliedEditing(PassRefPtr<EditCommand> cmd)
   1017 {
   1018     m_frame->document()->updateLayout();
   1019 
   1020     dispatchEditableContentChangedEvents(*cmd);
   1021 
   1022     VisibleSelection newSelection(cmd->startingSelection());
   1023     changeSelectionAfterCommand(newSelection, true, true);
   1024 
   1025     m_lastEditCommand = 0;
   1026     if (client())
   1027         client()->registerCommandForRedo(cmd);
   1028     respondToChangedContents(newSelection);
   1029 }
   1030 
   1031 void Editor::reappliedEditing(PassRefPtr<EditCommand> cmd)
   1032 {
   1033     m_frame->document()->updateLayout();
   1034 
   1035     dispatchEditableContentChangedEvents(*cmd);
   1036 
   1037     VisibleSelection newSelection(cmd->endingSelection());
   1038     changeSelectionAfterCommand(newSelection, true, true);
   1039 
   1040     m_lastEditCommand = 0;
   1041     if (client())
   1042         client()->registerCommandForUndo(cmd);
   1043     respondToChangedContents(newSelection);
   1044 }
   1045 
   1046 Editor::Editor(Frame* frame)
   1047     : m_frame(frame)
   1048     , m_deleteButtonController(adoptPtr(new DeleteButtonController(frame)))
   1049     , m_ignoreCompositionSelectionChange(false)
   1050     , m_shouldStartNewKillRingSequence(false)
   1051     // This is off by default, since most editors want this behavior (this matches IE but not FF).
   1052     , m_shouldStyleWithCSS(false)
   1053     , m_killRing(adoptPtr(new KillRing))
   1054     , m_spellChecker(adoptPtr(new SpellChecker(frame)))
   1055     , m_spellingCorrector(adoptPtr(new SpellingCorrectionController(frame)))
   1056     , m_areMarkedTextMatchesHighlighted(false)
   1057 {
   1058 }
   1059 
   1060 Editor::~Editor()
   1061 {
   1062 }
   1063 
   1064 void Editor::clear()
   1065 {
   1066     m_compositionNode = 0;
   1067     m_customCompositionUnderlines.clear();
   1068     m_shouldStyleWithCSS = false;
   1069 }
   1070 
   1071 bool Editor::insertText(const String& text, Event* triggeringEvent)
   1072 {
   1073     return m_frame->eventHandler()->handleTextInputEvent(text, triggeringEvent);
   1074 }
   1075 
   1076 bool Editor::insertTextForConfirmedComposition(const String& text)
   1077 {
   1078     return m_frame->eventHandler()->handleTextInputEvent(text, 0, TextEventInputComposition);
   1079 }
   1080 
   1081 bool Editor::insertTextWithoutSendingTextEvent(const String& text, bool selectInsertedText, TextEvent* triggeringEvent)
   1082 {
   1083     if (text.isEmpty())
   1084         return false;
   1085 
   1086     VisibleSelection selection = selectionForCommand(triggeringEvent);
   1087     if (!selection.isContentEditable())
   1088         return false;
   1089     RefPtr<Range> range = selection.toNormalizedRange();
   1090 
   1091     if (!shouldInsertText(text, range.get(), EditorInsertActionTyped))
   1092         return true;
   1093 
   1094     if (!text.isEmpty())
   1095         updateMarkersForWordsAffectedByEditing(text[0]);
   1096 
   1097     bool shouldConsiderApplyingAutocorrection = false;
   1098     if (text == " " || text == "\t")
   1099         shouldConsiderApplyingAutocorrection = true;
   1100 
   1101     if (text.length() == 1 && isPunct(text[0]) && !isAmbiguousBoundaryCharacter(text[0]))
   1102         shouldConsiderApplyingAutocorrection = true;
   1103 
   1104     bool autocorrectionWasApplied = shouldConsiderApplyingAutocorrection && m_spellingCorrector->applyAutocorrectionBeforeTypingIfAppropriate();
   1105 
   1106     // Get the selection to use for the event that triggered this insertText.
   1107     // If the event handler changed the selection, we may want to use a different selection
   1108     // that is contained in the event target.
   1109     selection = selectionForCommand(triggeringEvent);
   1110     if (selection.isContentEditable()) {
   1111         if (Node* selectionStart = selection.start().deprecatedNode()) {
   1112             RefPtr<Document> document = selectionStart->document();
   1113 
   1114             // Insert the text
   1115             TypingCommand::Options options = 0;
   1116             if (selectInsertedText)
   1117                 options |= TypingCommand::SelectInsertedText;
   1118             if (autocorrectionWasApplied)
   1119                 options |= TypingCommand::RetainAutocorrectionIndicator;
   1120             TypingCommand::insertText(document.get(), text, selection, options, triggeringEvent && triggeringEvent->isComposition() ? TypingCommand::TextCompositionConfirm : TypingCommand::TextCompositionNone);
   1121 
   1122             // Reveal the current selection
   1123             if (Frame* editedFrame = document->frame())
   1124                 if (Page* page = editedFrame->page())
   1125                     page->focusController()->focusedOrMainFrame()->selection()->revealSelection(ScrollAlignment::alignToEdgeIfNeeded);
   1126         }
   1127     }
   1128 
   1129     return true;
   1130 }
   1131 
   1132 bool Editor::insertLineBreak()
   1133 {
   1134     if (!canEdit())
   1135         return false;
   1136 
   1137     if (!shouldInsertText("\n", m_frame->selection()->toNormalizedRange().get(), EditorInsertActionTyped))
   1138         return true;
   1139 
   1140     bool autocorrectionIsApplied = m_spellingCorrector->applyAutocorrectionBeforeTypingIfAppropriate();
   1141     TypingCommand::insertLineBreak(m_frame->document(), autocorrectionIsApplied ? TypingCommand::RetainAutocorrectionIndicator : 0);
   1142     revealSelectionAfterEditingOperation();
   1143 
   1144     return true;
   1145 }
   1146 
   1147 bool Editor::insertParagraphSeparator()
   1148 {
   1149     if (!canEdit())
   1150         return false;
   1151 
   1152     if (!canEditRichly())
   1153         return insertLineBreak();
   1154 
   1155     if (!shouldInsertText("\n", m_frame->selection()->toNormalizedRange().get(), EditorInsertActionTyped))
   1156         return true;
   1157 
   1158     bool autocorrectionIsApplied = m_spellingCorrector->applyAutocorrectionBeforeTypingIfAppropriate();
   1159     TypingCommand::insertParagraphSeparator(m_frame->document(), autocorrectionIsApplied ? TypingCommand::RetainAutocorrectionIndicator : 0);
   1160     revealSelectionAfterEditingOperation();
   1161 
   1162     return true;
   1163 }
   1164 
   1165 void Editor::cut()
   1166 {
   1167     if (tryDHTMLCut())
   1168         return; // DHTML did the whole operation
   1169     if (!canCut()) {
   1170         systemBeep();
   1171         return;
   1172     }
   1173     RefPtr<Range> selection = selectedRange();
   1174     if (shouldDeleteRange(selection.get())) {
   1175         updateMarkersForWordsAffectedByEditing(true);
   1176         if (isNodeInTextFormControl(m_frame->selection()->start().deprecatedNode()))
   1177             Pasteboard::generalPasteboard()->writePlainText(selectedText());
   1178         else
   1179             Pasteboard::generalPasteboard()->writeSelection(selection.get(), canSmartCopyOrDelete(), m_frame);
   1180         didWriteSelectionToPasteboard();
   1181         deleteSelectionWithSmartDelete(canSmartCopyOrDelete());
   1182     }
   1183 }
   1184 
   1185 void Editor::copy()
   1186 {
   1187     if (tryDHTMLCopy())
   1188         return; // DHTML did the whole operation
   1189     if (!canCopy()) {
   1190         systemBeep();
   1191         return;
   1192     }
   1193 
   1194     if (isNodeInTextFormControl(m_frame->selection()->start().deprecatedNode()))
   1195         Pasteboard::generalPasteboard()->writePlainText(selectedText());
   1196     else {
   1197         Document* document = m_frame->document();
   1198         if (HTMLImageElement* imageElement = imageElementFromImageDocument(document))
   1199             Pasteboard::generalPasteboard()->writeImage(imageElement, document->url(), document->title());
   1200         else
   1201             Pasteboard::generalPasteboard()->writeSelection(selectedRange().get(), canSmartCopyOrDelete(), m_frame);
   1202     }
   1203 
   1204     didWriteSelectionToPasteboard();
   1205 }
   1206 
   1207 void Editor::paste()
   1208 {
   1209     ASSERT(m_frame->document());
   1210     if (tryDHTMLPaste())
   1211         return; // DHTML did the whole operation
   1212     if (!canPaste())
   1213         return;
   1214     updateMarkersForWordsAffectedByEditing(false);
   1215     CachedResourceLoader* loader = m_frame->document()->cachedResourceLoader();
   1216     loader->setAllowStaleResources(true);
   1217     if (m_frame->selection()->isContentRichlyEditable())
   1218         pasteWithPasteboard(Pasteboard::generalPasteboard(), true);
   1219     else
   1220         pasteAsPlainTextWithPasteboard(Pasteboard::generalPasteboard());
   1221     loader->setAllowStaleResources(false);
   1222 }
   1223 
   1224 void Editor::pasteAsPlainText()
   1225 {
   1226     if (tryDHTMLPaste())
   1227         return;
   1228     if (!canPaste())
   1229         return;
   1230     updateMarkersForWordsAffectedByEditing(false);
   1231     pasteAsPlainTextWithPasteboard(Pasteboard::generalPasteboard());
   1232 }
   1233 
   1234 void Editor::performDelete()
   1235 {
   1236     if (!canDelete()) {
   1237         systemBeep();
   1238         return;
   1239     }
   1240 
   1241     addToKillRing(selectedRange().get(), false);
   1242     deleteSelectionWithSmartDelete(canSmartCopyOrDelete());
   1243 
   1244     // clear the "start new kill ring sequence" setting, because it was set to true
   1245     // when the selection was updated by deleting the range
   1246     setStartNewKillRingSequence(false);
   1247 }
   1248 
   1249 void Editor::copyURL(const KURL& url, const String& title)
   1250 {
   1251     Pasteboard::generalPasteboard()->writeURL(url, title, m_frame);
   1252 }
   1253 
   1254 void Editor::copyImage(const HitTestResult& result)
   1255 {
   1256     KURL url = result.absoluteLinkURL();
   1257     if (url.isEmpty())
   1258         url = result.absoluteImageURL();
   1259 
   1260     Pasteboard::generalPasteboard()->writeImage(result.innerNonSharedNode(), url, result.altDisplayString());
   1261 }
   1262 
   1263 bool Editor::isContinuousSpellCheckingEnabled()
   1264 {
   1265     return client() && client()->isContinuousSpellCheckingEnabled();
   1266 }
   1267 
   1268 void Editor::toggleContinuousSpellChecking()
   1269 {
   1270     if (client())
   1271         client()->toggleContinuousSpellChecking();
   1272 }
   1273 
   1274 bool Editor::isGrammarCheckingEnabled()
   1275 {
   1276     return client() && client()->isGrammarCheckingEnabled();
   1277 }
   1278 
   1279 void Editor::toggleGrammarChecking()
   1280 {
   1281     if (client())
   1282         client()->toggleGrammarChecking();
   1283 }
   1284 
   1285 int Editor::spellCheckerDocumentTag()
   1286 {
   1287     return client() ? client()->spellCheckerDocumentTag() : 0;
   1288 }
   1289 
   1290 #if USE(AUTOMATIC_TEXT_REPLACEMENT)
   1291 
   1292 void Editor::uppercaseWord()
   1293 {
   1294     if (client())
   1295         client()->uppercaseWord();
   1296 }
   1297 
   1298 void Editor::lowercaseWord()
   1299 {
   1300     if (client())
   1301         client()->lowercaseWord();
   1302 }
   1303 
   1304 void Editor::capitalizeWord()
   1305 {
   1306     if (client())
   1307         client()->capitalizeWord();
   1308 }
   1309 
   1310 void Editor::showSubstitutionsPanel()
   1311 {
   1312     if (!client()) {
   1313         LOG_ERROR("No NSSpellChecker");
   1314         return;
   1315     }
   1316 
   1317     if (client()->substitutionsPanelIsShowing()) {
   1318         client()->showSubstitutionsPanel(false);
   1319         return;
   1320     }
   1321     client()->showSubstitutionsPanel(true);
   1322 }
   1323 
   1324 bool Editor::substitutionsPanelIsShowing()
   1325 {
   1326     if (!client())
   1327         return false;
   1328     return client()->substitutionsPanelIsShowing();
   1329 }
   1330 
   1331 void Editor::toggleSmartInsertDelete()
   1332 {
   1333     if (client())
   1334         client()->toggleSmartInsertDelete();
   1335 }
   1336 
   1337 bool Editor::isAutomaticQuoteSubstitutionEnabled()
   1338 {
   1339     return client() && client()->isAutomaticQuoteSubstitutionEnabled();
   1340 }
   1341 
   1342 void Editor::toggleAutomaticQuoteSubstitution()
   1343 {
   1344     if (client())
   1345         client()->toggleAutomaticQuoteSubstitution();
   1346 }
   1347 
   1348 bool Editor::isAutomaticLinkDetectionEnabled()
   1349 {
   1350     return client() && client()->isAutomaticLinkDetectionEnabled();
   1351 }
   1352 
   1353 void Editor::toggleAutomaticLinkDetection()
   1354 {
   1355     if (client())
   1356         client()->toggleAutomaticLinkDetection();
   1357 }
   1358 
   1359 bool Editor::isAutomaticDashSubstitutionEnabled()
   1360 {
   1361     return client() && client()->isAutomaticDashSubstitutionEnabled();
   1362 }
   1363 
   1364 void Editor::toggleAutomaticDashSubstitution()
   1365 {
   1366     if (client())
   1367         client()->toggleAutomaticDashSubstitution();
   1368 }
   1369 
   1370 bool Editor::isAutomaticTextReplacementEnabled()
   1371 {
   1372     return client() && client()->isAutomaticTextReplacementEnabled();
   1373 }
   1374 
   1375 void Editor::toggleAutomaticTextReplacement()
   1376 {
   1377     if (client())
   1378         client()->toggleAutomaticTextReplacement();
   1379 }
   1380 
   1381 bool Editor::isAutomaticSpellingCorrectionEnabled()
   1382 {
   1383     return m_spellingCorrector->isAutomaticSpellingCorrectionEnabled();
   1384 }
   1385 
   1386 void Editor::toggleAutomaticSpellingCorrection()
   1387 {
   1388     if (client())
   1389         client()->toggleAutomaticSpellingCorrection();
   1390 }
   1391 
   1392 #endif
   1393 
   1394 bool Editor::shouldEndEditing(Range* range)
   1395 {
   1396     return client() && client()->shouldEndEditing(range);
   1397 }
   1398 
   1399 bool Editor::shouldBeginEditing(Range* range)
   1400 {
   1401     return client() && client()->shouldBeginEditing(range);
   1402 }
   1403 
   1404 void Editor::clearUndoRedoOperations()
   1405 {
   1406     if (client())
   1407         client()->clearUndoRedoOperations();
   1408 }
   1409 
   1410 bool Editor::canUndo()
   1411 {
   1412     return client() && client()->canUndo();
   1413 }
   1414 
   1415 void Editor::undo()
   1416 {
   1417     if (client())
   1418         client()->undo();
   1419 }
   1420 
   1421 bool Editor::canRedo()
   1422 {
   1423     return client() && client()->canRedo();
   1424 }
   1425 
   1426 void Editor::redo()
   1427 {
   1428     if (client())
   1429         client()->redo();
   1430 }
   1431 
   1432 void Editor::didBeginEditing()
   1433 {
   1434     if (client())
   1435         client()->didBeginEditing();
   1436 }
   1437 
   1438 void Editor::didEndEditing()
   1439 {
   1440     if (client())
   1441         client()->didEndEditing();
   1442 }
   1443 
   1444 void Editor::didWriteSelectionToPasteboard()
   1445 {
   1446     if (client())
   1447         client()->didWriteSelectionToPasteboard();
   1448 }
   1449 
   1450 void Editor::toggleBold()
   1451 {
   1452     command("ToggleBold").execute();
   1453 }
   1454 
   1455 void Editor::toggleUnderline()
   1456 {
   1457     command("ToggleUnderline").execute();
   1458 }
   1459 
   1460 void Editor::setBaseWritingDirection(WritingDirection direction)
   1461 {
   1462     Node* focusedNode = frame()->document()->focusedNode();
   1463     if (focusedNode && (focusedNode->hasTagName(textareaTag) || (focusedNode->hasTagName(inputTag) && static_cast<HTMLInputElement*>(focusedNode)->isTextField()))) {
   1464         if (direction == NaturalWritingDirection)
   1465             return;
   1466         toHTMLElement(focusedNode)->setAttribute(dirAttr, direction == LeftToRightWritingDirection ? "ltr" : "rtl");
   1467         frame()->document()->updateStyleIfNeeded();
   1468         return;
   1469     }
   1470 
   1471     RefPtr<CSSMutableStyleDeclaration> style = CSSMutableStyleDeclaration::create();
   1472     style->setProperty(CSSPropertyDirection, direction == LeftToRightWritingDirection ? "ltr" : direction == RightToLeftWritingDirection ? "rtl" : "inherit", false);
   1473     applyParagraphStyleToSelection(style.get(), EditActionSetWritingDirection);
   1474 }
   1475 
   1476 void Editor::selectComposition()
   1477 {
   1478     RefPtr<Range> range = compositionRange();
   1479     if (!range)
   1480         return;
   1481 
   1482     // The composition can start inside a composed character sequence, so we have to override checks.
   1483     // See <http://bugs.webkit.org/show_bug.cgi?id=15781>
   1484     VisibleSelection selection;
   1485     selection.setWithoutValidation(range->startPosition(), range->endPosition());
   1486     m_frame->selection()->setSelection(selection, 0);
   1487 }
   1488 
   1489 void Editor::confirmComposition()
   1490 {
   1491     if (!m_compositionNode)
   1492         return;
   1493     confirmComposition(m_compositionNode->data().substring(m_compositionStart, m_compositionEnd - m_compositionStart), false);
   1494 }
   1495 
   1496 void Editor::confirmCompositionWithoutDisturbingSelection()
   1497 {
   1498     if (!m_compositionNode)
   1499         return;
   1500     confirmComposition(m_compositionNode->data().substring(m_compositionStart, m_compositionEnd - m_compositionStart), true);
   1501 }
   1502 
   1503 void Editor::confirmComposition(const String& text)
   1504 {
   1505     confirmComposition(text, false);
   1506 }
   1507 
   1508 void Editor::confirmComposition(const String& text, bool preserveSelection)
   1509 {
   1510     UserTypingGestureIndicator typingGestureIndicator(m_frame);
   1511 
   1512     setIgnoreCompositionSelectionChange(true);
   1513 
   1514     VisibleSelection oldSelection = m_frame->selection()->selection();
   1515 
   1516     selectComposition();
   1517 
   1518     if (m_frame->selection()->isNone()) {
   1519         setIgnoreCompositionSelectionChange(false);
   1520         return;
   1521     }
   1522 
   1523     // Dispatch a compositionend event to the focused node.
   1524     // We should send this event before sending a TextEvent as written in Section 6.2.2 and 6.2.3 of
   1525     // the DOM Event specification.
   1526     Node* target = m_frame->document()->focusedNode();
   1527     if (target) {
   1528         RefPtr<CompositionEvent> event = CompositionEvent::create(eventNames().compositionendEvent, m_frame->domWindow(), text);
   1529         ExceptionCode ec = 0;
   1530         target->dispatchEvent(event, ec);
   1531     }
   1532 
   1533     // If text is empty, then delete the old composition here.  If text is non-empty, InsertTextCommand::input
   1534     // will delete the old composition with an optimized replace operation.
   1535     if (text.isEmpty())
   1536         TypingCommand::deleteSelection(m_frame->document(), 0);
   1537 
   1538     m_compositionNode = 0;
   1539     m_customCompositionUnderlines.clear();
   1540 
   1541     insertTextForConfirmedComposition(text);
   1542 
   1543     if (preserveSelection) {
   1544         m_frame->selection()->setSelection(oldSelection, 0);
   1545         // An open typing command that disagrees about current selection would cause issues with typing later on.
   1546         TypingCommand::closeTyping(m_lastEditCommand.get());
   1547     }
   1548 
   1549     setIgnoreCompositionSelectionChange(false);
   1550 }
   1551 
   1552 void Editor::setComposition(const String& text, const Vector<CompositionUnderline>& underlines, unsigned selectionStart, unsigned selectionEnd)
   1553 {
   1554     UserTypingGestureIndicator typingGestureIndicator(m_frame);
   1555 
   1556     setIgnoreCompositionSelectionChange(true);
   1557 
   1558     // Updates styles before setting selection for composition to prevent
   1559     // inserting the previous composition text into text nodes oddly.
   1560     // See https://bugs.webkit.org/show_bug.cgi?id=46868
   1561     m_frame->document()->updateStyleIfNeeded();
   1562 
   1563     selectComposition();
   1564 
   1565     if (m_frame->selection()->isNone()) {
   1566         setIgnoreCompositionSelectionChange(false);
   1567         return;
   1568     }
   1569 
   1570     Node* target = m_frame->document()->focusedNode();
   1571     if (target) {
   1572         // Dispatch an appropriate composition event to the focused node.
   1573         // We check the composition status and choose an appropriate composition event since this
   1574         // function is used for three purposes:
   1575         // 1. Starting a new composition.
   1576         //    Send a compositionstart event when this function creates a new composition node, i.e.
   1577         //    m_compositionNode == 0 && !text.isEmpty().
   1578         // 2. Updating the existing composition node.
   1579         //    Send a compositionupdate event when this function updates the existing composition
   1580         //    node, i.e. m_compositionNode != 0 && !text.isEmpty().
   1581         // 3. Canceling the ongoing composition.
   1582         //    Send a compositionend event when function deletes the existing composition node, i.e.
   1583         //    m_compositionNode != 0 && test.isEmpty().
   1584         RefPtr<CompositionEvent> event;
   1585         if (!m_compositionNode) {
   1586             // We should send a compositionstart event only when the given text is not empty because this
   1587             // function doesn't create a composition node when the text is empty.
   1588             if (!text.isEmpty())
   1589                 event = CompositionEvent::create(eventNames().compositionstartEvent, m_frame->domWindow(), text);
   1590         } else {
   1591             if (!text.isEmpty())
   1592                 event = CompositionEvent::create(eventNames().compositionupdateEvent, m_frame->domWindow(), text);
   1593             else
   1594               event = CompositionEvent::create(eventNames().compositionendEvent, m_frame->domWindow(), text);
   1595         }
   1596         ExceptionCode ec = 0;
   1597         if (event.get())
   1598             target->dispatchEvent(event, ec);
   1599     }
   1600 
   1601     // If text is empty, then delete the old composition here.  If text is non-empty, InsertTextCommand::input
   1602     // will delete the old composition with an optimized replace operation.
   1603     if (text.isEmpty())
   1604         TypingCommand::deleteSelection(m_frame->document(), TypingCommand::PreventSpellChecking);
   1605 
   1606     m_compositionNode = 0;
   1607     m_customCompositionUnderlines.clear();
   1608 
   1609     if (!text.isEmpty()) {
   1610         TypingCommand::insertText(m_frame->document(), text, TypingCommand::SelectInsertedText | TypingCommand::PreventSpellChecking, TypingCommand::TextCompositionUpdate);
   1611 
   1612         // Find out what node has the composition now.
   1613         Position base = m_frame->selection()->base().downstream();
   1614         Position extent = m_frame->selection()->extent();
   1615         Node* baseNode = base.deprecatedNode();
   1616         unsigned baseOffset = base.deprecatedEditingOffset();
   1617         Node* extentNode = extent.deprecatedNode();
   1618         unsigned extentOffset = extent.deprecatedEditingOffset();
   1619 
   1620         if (baseNode && baseNode == extentNode && baseNode->isTextNode() && baseOffset + text.length() == extentOffset) {
   1621             m_compositionNode = static_cast<Text*>(baseNode);
   1622             m_compositionStart = baseOffset;
   1623             m_compositionEnd = extentOffset;
   1624             m_customCompositionUnderlines = underlines;
   1625             size_t numUnderlines = m_customCompositionUnderlines.size();
   1626             for (size_t i = 0; i < numUnderlines; ++i) {
   1627                 m_customCompositionUnderlines[i].startOffset += baseOffset;
   1628                 m_customCompositionUnderlines[i].endOffset += baseOffset;
   1629             }
   1630             if (baseNode->renderer())
   1631                 baseNode->renderer()->repaint();
   1632 
   1633             unsigned start = min(baseOffset + selectionStart, extentOffset);
   1634             unsigned end = min(max(start, baseOffset + selectionEnd), extentOffset);
   1635             RefPtr<Range> selectedRange = Range::create(baseNode->document(), baseNode, start, baseNode, end);
   1636             m_frame->selection()->setSelectedRange(selectedRange.get(), DOWNSTREAM, false);
   1637         }
   1638     }
   1639 
   1640     setIgnoreCompositionSelectionChange(false);
   1641 }
   1642 
   1643 void Editor::ignoreSpelling()
   1644 {
   1645     if (!client())
   1646         return;
   1647 
   1648     RefPtr<Range> selectedRange = frame()->selection()->toNormalizedRange();
   1649     if (selectedRange)
   1650         frame()->document()->markers()->removeMarkers(selectedRange.get(), DocumentMarker::Spelling);
   1651 
   1652     String text = selectedText();
   1653     ASSERT(text.length());
   1654     textChecker()->ignoreWordInSpellDocument(text);
   1655 }
   1656 
   1657 void Editor::learnSpelling()
   1658 {
   1659     if (!client())
   1660         return;
   1661 
   1662     // FIXME: On Mac OS X, when use "learn" button on "Spelling and Grammar" panel, we don't call this function. It should remove misspelling markers around the learned word, see <rdar://problem/5396072>.
   1663 
   1664     RefPtr<Range> selectedRange = frame()->selection()->toNormalizedRange();
   1665     if (selectedRange)
   1666         frame()->document()->markers()->removeMarkers(selectedRange.get(), DocumentMarker::Spelling);
   1667 
   1668     String text = selectedText();
   1669     ASSERT(text.length());
   1670     textChecker()->learnWord(text);
   1671 }
   1672 
   1673 void Editor::advanceToNextMisspelling(bool startBeforeSelection)
   1674 {
   1675     ExceptionCode ec = 0;
   1676 
   1677     // The basic approach is to search in two phases - from the selection end to the end of the doc, and
   1678     // then we wrap and search from the doc start to (approximately) where we started.
   1679 
   1680     // Start at the end of the selection, search to edge of document.  Starting at the selection end makes
   1681     // repeated "check spelling" commands work.
   1682     VisibleSelection selection(frame()->selection()->selection());
   1683     RefPtr<Range> spellingSearchRange(rangeOfContents(frame()->document()));
   1684 
   1685     bool startedWithSelection = false;
   1686     if (selection.start().deprecatedNode()) {
   1687         startedWithSelection = true;
   1688         if (startBeforeSelection) {
   1689             VisiblePosition start(selection.visibleStart());
   1690             // We match AppKit's rule: Start 1 character before the selection.
   1691             VisiblePosition oneBeforeStart = start.previous();
   1692             setStart(spellingSearchRange.get(), oneBeforeStart.isNotNull() ? oneBeforeStart : start);
   1693         } else
   1694             setStart(spellingSearchRange.get(), selection.visibleEnd());
   1695     }
   1696 
   1697     Position position = spellingSearchRange->startPosition();
   1698     if (!isEditablePosition(position)) {
   1699         // This shouldn't happen in very often because the Spelling menu items aren't enabled unless the
   1700         // selection is editable.
   1701         // This can happen in Mail for a mix of non-editable and editable content (like Stationary),
   1702         // when spell checking the whole document before sending the message.
   1703         // In that case the document might not be editable, but there are editable pockets that need to be spell checked.
   1704 
   1705         position = firstEditablePositionAfterPositionInRoot(position, frame()->document()->documentElement()).deepEquivalent();
   1706         if (position.isNull())
   1707             return;
   1708 
   1709         Position rangeCompliantPosition = position.parentAnchoredEquivalent();
   1710         spellingSearchRange->setStart(rangeCompliantPosition.deprecatedNode(), rangeCompliantPosition.deprecatedEditingOffset(), ec);
   1711         startedWithSelection = false; // won't need to wrap
   1712     }
   1713 
   1714     // topNode defines the whole range we want to operate on
   1715     Node* topNode = highestEditableRoot(position);
   1716     // FIXME: lastOffsetForEditing() is wrong here if editingIgnoresContent(highestEditableRoot()) returns true (e.g. a <table>)
   1717     spellingSearchRange->setEnd(topNode, lastOffsetForEditing(topNode), ec);
   1718 
   1719     // If spellingSearchRange starts in the middle of a word, advance to the next word so we start checking
   1720     // at a word boundary. Going back by one char and then forward by a word does the trick.
   1721     if (startedWithSelection) {
   1722         VisiblePosition oneBeforeStart = startVisiblePosition(spellingSearchRange.get(), DOWNSTREAM).previous();
   1723         if (oneBeforeStart.isNotNull())
   1724             setStart(spellingSearchRange.get(), endOfWord(oneBeforeStart));
   1725         // else we were already at the start of the editable node
   1726     }
   1727 
   1728     if (spellingSearchRange->collapsed(ec))
   1729         return; // nothing to search in
   1730 
   1731     // Get the spell checker if it is available
   1732     if (!client())
   1733         return;
   1734 
   1735     // We go to the end of our first range instead of the start of it, just to be sure
   1736     // we don't get foiled by any word boundary problems at the start.  It means we might
   1737     // do a tiny bit more searching.
   1738     Node* searchEndNodeAfterWrap = spellingSearchRange->endContainer(ec);
   1739     int searchEndOffsetAfterWrap = spellingSearchRange->endOffset(ec);
   1740 
   1741     int misspellingOffset = 0;
   1742     GrammarDetail grammarDetail;
   1743     int grammarPhraseOffset = 0;
   1744     RefPtr<Range> grammarSearchRange;
   1745     String badGrammarPhrase;
   1746     String misspelledWord;
   1747 
   1748 #if USE(UNIFIED_TEXT_CHECKING)
   1749     grammarSearchRange = spellingSearchRange->cloneRange(ec);
   1750     bool isSpelling = true;
   1751     int foundOffset = 0;
   1752     String foundItem = TextCheckingHelper(client(), spellingSearchRange).findFirstMisspellingOrBadGrammar(isGrammarCheckingEnabled(), isSpelling, foundOffset, grammarDetail);
   1753     if (isSpelling) {
   1754         misspelledWord = foundItem;
   1755         misspellingOffset = foundOffset;
   1756     } else {
   1757         badGrammarPhrase = foundItem;
   1758         grammarPhraseOffset = foundOffset;
   1759     }
   1760 #else
   1761     RefPtr<Range> firstMisspellingRange;
   1762     misspelledWord = TextCheckingHelper(client(), spellingSearchRange).findFirstMisspelling(misspellingOffset, false, firstMisspellingRange);
   1763 
   1764 #if USE(GRAMMAR_CHECKING)
   1765     // Search for bad grammar that occurs prior to the next misspelled word (if any)
   1766     grammarSearchRange = spellingSearchRange->cloneRange(ec);
   1767     if (!misspelledWord.isEmpty()) {
   1768         // Stop looking at start of next misspelled word
   1769         CharacterIterator chars(grammarSearchRange.get());
   1770         chars.advance(misspellingOffset);
   1771         grammarSearchRange->setEnd(chars.range()->startContainer(ec), chars.range()->startOffset(ec), ec);
   1772     }
   1773 
   1774     if (isGrammarCheckingEnabled())
   1775         badGrammarPhrase = TextCheckingHelper(client(), grammarSearchRange).findFirstBadGrammar(grammarDetail, grammarPhraseOffset, false);
   1776 #endif
   1777 #endif
   1778 
   1779     // 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
   1780     // block rather than at a selection).
   1781     if (startedWithSelection && !misspelledWord && !badGrammarPhrase) {
   1782         spellingSearchRange->setStart(topNode, 0, ec);
   1783         // going until the end of the very first chunk we tested is far enough
   1784         spellingSearchRange->setEnd(searchEndNodeAfterWrap, searchEndOffsetAfterWrap, ec);
   1785 
   1786 #if USE(UNIFIED_TEXT_CHECKING)
   1787         grammarSearchRange = spellingSearchRange->cloneRange(ec);
   1788         foundItem = TextCheckingHelper(client(), spellingSearchRange).findFirstMisspellingOrBadGrammar(isGrammarCheckingEnabled(), isSpelling, foundOffset, grammarDetail);
   1789         if (isSpelling) {
   1790             misspelledWord = foundItem;
   1791             misspellingOffset = foundOffset;
   1792         } else {
   1793             badGrammarPhrase = foundItem;
   1794             grammarPhraseOffset = foundOffset;
   1795         }
   1796 #else
   1797         misspelledWord = TextCheckingHelper(client(), spellingSearchRange).findFirstMisspelling(misspellingOffset, false, firstMisspellingRange);
   1798 
   1799 #if USE(GRAMMAR_CHECKING)
   1800         grammarSearchRange = spellingSearchRange->cloneRange(ec);
   1801         if (!misspelledWord.isEmpty()) {
   1802             // Stop looking at start of next misspelled word
   1803             CharacterIterator chars(grammarSearchRange.get());
   1804             chars.advance(misspellingOffset);
   1805             grammarSearchRange->setEnd(chars.range()->startContainer(ec), chars.range()->startOffset(ec), ec);
   1806         }
   1807 
   1808         if (isGrammarCheckingEnabled())
   1809             badGrammarPhrase = TextCheckingHelper(client(), grammarSearchRange).findFirstBadGrammar(grammarDetail, grammarPhraseOffset, false);
   1810 #endif
   1811 #endif
   1812     }
   1813 
   1814     if (!badGrammarPhrase.isEmpty()) {
   1815         ASSERT(WTF_USE_GRAMMAR_CHECKING);
   1816         // We found bad grammar. Since we only searched for bad grammar up to the first misspelled word, the bad grammar
   1817         // takes precedence and we ignore any potential misspelled word. Select the grammar detail, update the spelling
   1818         // panel, and store a marker so we draw the green squiggle later.
   1819 
   1820         ASSERT(badGrammarPhrase.length() > 0);
   1821         ASSERT(grammarDetail.location != -1 && grammarDetail.length > 0);
   1822 
   1823         // FIXME 4859190: This gets confused with doubled punctuation at the end of a paragraph
   1824         RefPtr<Range> badGrammarRange = TextIterator::subrange(grammarSearchRange.get(), grammarPhraseOffset + grammarDetail.location, grammarDetail.length);
   1825         frame()->selection()->setSelection(VisibleSelection(badGrammarRange.get(), SEL_DEFAULT_AFFINITY));
   1826         frame()->selection()->revealSelection();
   1827 
   1828         client()->updateSpellingUIWithGrammarString(badGrammarPhrase, grammarDetail);
   1829         frame()->document()->markers()->addMarker(badGrammarRange.get(), DocumentMarker::Grammar, grammarDetail.userDescription);
   1830     } else if (!misspelledWord.isEmpty()) {
   1831         // We found a misspelling, but not any earlier bad grammar. Select the misspelling, update the spelling panel, and store
   1832         // a marker so we draw the red squiggle later.
   1833 
   1834         RefPtr<Range> misspellingRange = TextIterator::subrange(spellingSearchRange.get(), misspellingOffset, misspelledWord.length());
   1835         frame()->selection()->setSelection(VisibleSelection(misspellingRange.get(), DOWNSTREAM));
   1836         frame()->selection()->revealSelection();
   1837 
   1838         client()->updateSpellingUIWithMisspelledWord(misspelledWord);
   1839         frame()->document()->markers()->addMarker(misspellingRange.get(), DocumentMarker::Spelling);
   1840     }
   1841 }
   1842 
   1843 bool Editor::isSelectionMisspelled()
   1844 {
   1845     String selectedString = selectedText();
   1846     int length = selectedString.length();
   1847     if (!length)
   1848         return false;
   1849 
   1850     if (!client())
   1851         return false;
   1852 
   1853     int misspellingLocation = -1;
   1854     int misspellingLength = 0;
   1855     textChecker()->checkSpellingOfString(selectedString.characters(), length, &misspellingLocation, &misspellingLength);
   1856 
   1857     // The selection only counts as misspelled if the selected text is exactly one misspelled word
   1858     if (misspellingLength != length)
   1859         return false;
   1860 
   1861     // Update the spelling panel to be displaying this error (whether or not the spelling panel is on screen).
   1862     // This is necessary to make a subsequent call to [NSSpellChecker ignoreWord:inSpellDocumentWithTag:] work
   1863     // correctly; that call behaves differently based on whether the spelling panel is displaying a misspelling
   1864     // or a grammar error.
   1865     client()->updateSpellingUIWithMisspelledWord(selectedString);
   1866 
   1867     return true;
   1868 }
   1869 
   1870 bool Editor::isSelectionUngrammatical()
   1871 {
   1872 #if USE(GRAMMAR_CHECKING)
   1873     Vector<String> ignoredGuesses;
   1874     return TextCheckingHelper(client(), frame()->selection()->toNormalizedRange()).isUngrammatical(ignoredGuesses);
   1875 #else
   1876     return false;
   1877 #endif
   1878 }
   1879 
   1880 Vector<String> Editor::guessesForUngrammaticalSelection()
   1881 {
   1882 #if USE(GRAMMAR_CHECKING)
   1883     Vector<String> guesses;
   1884     // Ignore the result of isUngrammatical; we just want the guesses, whether or not there are any
   1885     TextCheckingHelper(client(), frame()->selection()->toNormalizedRange()).isUngrammatical(guesses);
   1886     return guesses;
   1887 #else
   1888     return Vector<String>();
   1889 #endif
   1890 }
   1891 
   1892 Vector<String> Editor::guessesForMisspelledSelection()
   1893 {
   1894     String selectedString = selectedText();
   1895     ASSERT(selectedString.length());
   1896 
   1897     Vector<String> guesses;
   1898     if (client())
   1899         textChecker()->getGuessesForWord(selectedString, String(), guesses);
   1900     return guesses;
   1901 }
   1902 
   1903 Vector<String> Editor::guessesForMisspelledOrUngrammaticalSelection(bool& misspelled, bool& ungrammatical)
   1904 {
   1905 #if USE(UNIFIED_TEXT_CHECKING)
   1906     return TextCheckingHelper(client(), frame()->selection()->toNormalizedRange()).guessesForMisspelledOrUngrammaticalRange(isGrammarCheckingEnabled(), misspelled, ungrammatical);
   1907 #else
   1908     misspelled = isSelectionMisspelled();
   1909     if (misspelled) {
   1910         ungrammatical = false;
   1911         return guessesForMisspelledSelection();
   1912     }
   1913     if (isGrammarCheckingEnabled() && isSelectionUngrammatical()) {
   1914         ungrammatical = true;
   1915         return guessesForUngrammaticalSelection();
   1916     }
   1917     ungrammatical = false;
   1918     return Vector<String>();
   1919 #endif
   1920 }
   1921 
   1922 void Editor::showSpellingGuessPanel()
   1923 {
   1924     if (!client()) {
   1925         LOG_ERROR("No NSSpellChecker");
   1926         return;
   1927     }
   1928 
   1929 #ifndef BUILDING_ON_TIGER
   1930     // Post-Tiger, this menu item is a show/hide toggle, to match AppKit. Leave Tiger behavior alone
   1931     // to match rest of OS X.
   1932     if (client()->spellingUIIsShowing()) {
   1933         client()->showSpellingUI(false);
   1934         return;
   1935     }
   1936 #endif
   1937 
   1938     advanceToNextMisspelling(true);
   1939     client()->showSpellingUI(true);
   1940 }
   1941 
   1942 bool Editor::spellingPanelIsShowing()
   1943 {
   1944     if (!client())
   1945         return false;
   1946     return client()->spellingUIIsShowing();
   1947 }
   1948 
   1949 void Editor::clearMisspellingsAndBadGrammar(const VisibleSelection &movingSelection)
   1950 {
   1951     RefPtr<Range> selectedRange = movingSelection.toNormalizedRange();
   1952     if (selectedRange) {
   1953         frame()->document()->markers()->removeMarkers(selectedRange.get(), DocumentMarker::Spelling);
   1954         frame()->document()->markers()->removeMarkers(selectedRange.get(), DocumentMarker::Grammar);
   1955     }
   1956 }
   1957 
   1958 void Editor::markMisspellingsAndBadGrammar(const VisibleSelection &movingSelection)
   1959 {
   1960     bool markSpelling = isContinuousSpellCheckingEnabled();
   1961     bool markGrammar = markSpelling && isGrammarCheckingEnabled();
   1962 
   1963     if (markSpelling) {
   1964         RefPtr<Range> unusedFirstMisspellingRange;
   1965         markMisspellings(movingSelection, unusedFirstMisspellingRange);
   1966     }
   1967 
   1968     if (markGrammar)
   1969         markBadGrammar(movingSelection);
   1970 }
   1971 
   1972 void Editor::markMisspellingsAfterTypingToWord(const VisiblePosition &wordStart, const VisibleSelection& selectionAfterTyping, bool doReplacement)
   1973 {
   1974 #if USE(UNIFIED_TEXT_CHECKING)
   1975     m_spellingCorrector->applyPendingCorrection(selectionAfterTyping);
   1976 
   1977     TextCheckingOptions textCheckingOptions = 0;
   1978     if (isContinuousSpellCheckingEnabled())
   1979         textCheckingOptions |= MarkSpelling;
   1980 
   1981 #if USE(AUTOMATIC_TEXT_REPLACEMENT)
   1982     if (doReplacement
   1983         && (isAutomaticQuoteSubstitutionEnabled()
   1984             || isAutomaticLinkDetectionEnabled()
   1985             || isAutomaticDashSubstitutionEnabled()
   1986             || isAutomaticTextReplacementEnabled()
   1987             || ((textCheckingOptions & MarkSpelling) && isAutomaticSpellingCorrectionEnabled())))
   1988         textCheckingOptions |= PerformReplacement;
   1989 #endif
   1990     if (!textCheckingOptions & (MarkSpelling | PerformReplacement))
   1991         return;
   1992 
   1993     if (isGrammarCheckingEnabled())
   1994         textCheckingOptions |= MarkGrammar;
   1995 
   1996     VisibleSelection adjacentWords = VisibleSelection(startOfWord(wordStart, LeftWordIfOnBoundary), endOfWord(wordStart, RightWordIfOnBoundary));
   1997     if (textCheckingOptions & MarkGrammar) {
   1998         VisibleSelection selectedSentence = VisibleSelection(startOfSentence(wordStart), endOfSentence(wordStart));
   1999         markAllMisspellingsAndBadGrammarInRanges(textCheckingOptions, adjacentWords.toNormalizedRange().get(), selectedSentence.toNormalizedRange().get());
   2000     } else {
   2001         markAllMisspellingsAndBadGrammarInRanges(textCheckingOptions, adjacentWords.toNormalizedRange().get(), adjacentWords.toNormalizedRange().get());
   2002     }
   2003 
   2004 #else
   2005     UNUSED_PARAM(selectionAfterTyping);
   2006     UNUSED_PARAM(doReplacement);
   2007 
   2008     if (!isContinuousSpellCheckingEnabled())
   2009         return;
   2010 
   2011     // Check spelling of one word
   2012     RefPtr<Range> misspellingRange;
   2013     markMisspellings(VisibleSelection(startOfWord(wordStart, LeftWordIfOnBoundary), endOfWord(wordStart, RightWordIfOnBoundary)), misspellingRange);
   2014 
   2015     // Autocorrect the misspelled word.
   2016     if (!misspellingRange)
   2017         return;
   2018 
   2019     // Get the misspelled word.
   2020     const String misspelledWord = plainText(misspellingRange.get());
   2021     String autocorrectedString = textChecker()->getAutoCorrectSuggestionForMisspelledWord(misspelledWord);
   2022 
   2023     // If autocorrected word is non empty, replace the misspelled word by this word.
   2024     if (!autocorrectedString.isEmpty()) {
   2025         VisibleSelection newSelection(misspellingRange.get(), DOWNSTREAM);
   2026         if (newSelection != frame()->selection()->selection()) {
   2027             if (!frame()->selection()->shouldChangeSelection(newSelection))
   2028                 return;
   2029             frame()->selection()->setSelection(newSelection);
   2030         }
   2031 
   2032         if (!frame()->editor()->shouldInsertText(autocorrectedString, misspellingRange.get(), EditorInsertActionTyped))
   2033             return;
   2034         frame()->editor()->replaceSelectionWithText(autocorrectedString, false, false);
   2035 
   2036         // Reset the charet one character further.
   2037         frame()->selection()->moveTo(frame()->selection()->end());
   2038         frame()->selection()->modify(SelectionController::AlterationMove, DirectionForward, CharacterGranularity);
   2039     }
   2040 
   2041     if (!isGrammarCheckingEnabled())
   2042         return;
   2043 
   2044     // Check grammar of entire sentence
   2045     markBadGrammar(VisibleSelection(startOfSentence(wordStart), endOfSentence(wordStart)));
   2046 #endif
   2047 }
   2048 
   2049 void Editor::markMisspellingsOrBadGrammar(const VisibleSelection& selection, bool checkSpelling, RefPtr<Range>& firstMisspellingRange)
   2050 {
   2051     // This function is called with a selection already expanded to word boundaries.
   2052     // Might be nice to assert that here.
   2053 
   2054     // This function is used only for as-you-type checking, so if that's off we do nothing. Note that
   2055     // grammar checking can only be on if spell checking is also on.
   2056     if (!isContinuousSpellCheckingEnabled())
   2057         return;
   2058 
   2059     RefPtr<Range> searchRange(selection.toNormalizedRange());
   2060     if (!searchRange)
   2061         return;
   2062 
   2063     // If we're not in an editable node, bail.
   2064     Node* editableNode = searchRange->startContainer();
   2065     if (!editableNode || !editableNode->rendererIsEditable())
   2066         return;
   2067 
   2068     if (!isSpellCheckingEnabledFor(editableNode))
   2069         return;
   2070 
   2071     // Get the spell checker if it is available
   2072     if (!client())
   2073         return;
   2074 
   2075     TextCheckingHelper checker(client(), searchRange);
   2076     if (checkSpelling)
   2077         checker.markAllMisspellings(firstMisspellingRange);
   2078     else {
   2079         ASSERT(WTF_USE_GRAMMAR_CHECKING);
   2080         if (isGrammarCheckingEnabled())
   2081             checker.markAllBadGrammar();
   2082     }
   2083 }
   2084 
   2085 bool Editor::isSpellCheckingEnabledFor(Node* node) const
   2086 {
   2087     if (!node)
   2088         return false;
   2089     const Element* focusedElement = node->isElementNode() ? toElement(node) : node->parentElement();
   2090     if (!focusedElement)
   2091         return false;
   2092     return focusedElement->isSpellCheckingEnabled();
   2093 }
   2094 
   2095 bool Editor::isSpellCheckingEnabledInFocusedNode() const
   2096 {
   2097     return isSpellCheckingEnabledFor(m_frame->selection()->start().deprecatedNode());
   2098 }
   2099 
   2100 void Editor::markMisspellings(const VisibleSelection& selection, RefPtr<Range>& firstMisspellingRange)
   2101 {
   2102     markMisspellingsOrBadGrammar(selection, true, firstMisspellingRange);
   2103 }
   2104 
   2105 void Editor::markBadGrammar(const VisibleSelection& selection)
   2106 {
   2107     ASSERT(WTF_USE_GRAMMAR_CHECKING);
   2108     RefPtr<Range> firstMisspellingRange;
   2109     markMisspellingsOrBadGrammar(selection, false, firstMisspellingRange);
   2110 }
   2111 
   2112 void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions textCheckingOptions, Range* spellingRange, Range* grammarRange)
   2113 {
   2114 #if USE(UNIFIED_TEXT_CHECKING)
   2115     // There shouldn't be pending autocorrection at this moment.
   2116     ASSERT(!m_spellingCorrector->hasPendingCorrection());
   2117 
   2118     bool shouldMarkSpelling = textCheckingOptions & MarkSpelling;
   2119     bool shouldMarkGrammar = textCheckingOptions & MarkGrammar;
   2120     bool shouldPerformReplacement = textCheckingOptions & PerformReplacement;
   2121     bool shouldShowCorrectionPanel = textCheckingOptions & ShowCorrectionPanel;
   2122     bool shouldCheckForCorrection = shouldShowCorrectionPanel || (textCheckingOptions & CheckForCorrection);
   2123 
   2124     // This function is called with selections already expanded to word boundaries.
   2125     ExceptionCode ec = 0;
   2126     if (!client() || !spellingRange || (shouldMarkGrammar && !grammarRange))
   2127         return;
   2128 
   2129     // If we're not in an editable node, bail.
   2130     Node* editableNode = spellingRange->startContainer();
   2131     if (!editableNode || !editableNode->rendererIsEditable())
   2132         return;
   2133 
   2134     if (!isSpellCheckingEnabledFor(editableNode))
   2135         return;
   2136 
   2137     // Expand the range to encompass entire paragraphs, since text checking needs that much context.
   2138     int selectionOffset = 0;
   2139     int ambiguousBoundaryOffset = -1;
   2140     bool selectionChanged = false;
   2141     bool restoreSelectionAfterChange = false;
   2142     bool adjustSelectionForParagraphBoundaries = false;
   2143 
   2144     TextCheckingParagraph spellingParagraph(spellingRange);
   2145     TextCheckingParagraph grammarParagraph(shouldMarkGrammar ? grammarRange : 0);
   2146 
   2147     if (shouldMarkGrammar ? (spellingParagraph.isRangeEmpty() && grammarParagraph.isEmpty()) : spellingParagraph.isEmpty())
   2148         return;
   2149 
   2150     if (shouldPerformReplacement || shouldMarkSpelling || shouldCheckForCorrection) {
   2151         if (m_frame->selection()->selectionType() == VisibleSelection::CaretSelection) {
   2152             // Attempt to save the caret position so we can restore it later if needed
   2153             Position caretPosition = m_frame->selection()->end();
   2154             int offset = spellingParagraph.offsetTo(caretPosition, ec);
   2155             if (!ec) {
   2156                 selectionOffset = offset;
   2157                 restoreSelectionAfterChange = true;
   2158                 if (selectionOffset > 0 && (selectionOffset > spellingParagraph.textLength() || spellingParagraph.textCharAt(selectionOffset - 1) == newlineCharacter))
   2159                     adjustSelectionForParagraphBoundaries = true;
   2160                 if (selectionOffset > 0 && selectionOffset <= spellingParagraph.textLength() && isAmbiguousBoundaryCharacter(spellingParagraph.textCharAt(selectionOffset - 1)))
   2161                     ambiguousBoundaryOffset = selectionOffset - 1;
   2162             }
   2163         }
   2164     }
   2165 
   2166     Vector<TextCheckingResult> results;
   2167     if (shouldMarkGrammar)
   2168         textChecker()->checkTextOfParagraph(grammarParagraph.textCharacters(), grammarParagraph.textLength(),
   2169                                             textCheckingTypeMaskFor(textCheckingOptions), results);
   2170     else
   2171         textChecker()->checkTextOfParagraph(spellingParagraph.textCharacters(), spellingParagraph.textLength(),
   2172                                             textCheckingTypeMaskFor(textCheckingOptions), results);
   2173 
   2174 
   2175     // If this checking is only for showing correction panel, we shouldn't bother to mark misspellings.
   2176     if (shouldShowCorrectionPanel)
   2177         shouldMarkSpelling = false;
   2178 
   2179     int offsetDueToReplacement = 0;
   2180 
   2181     for (unsigned i = 0; i < results.size(); i++) {
   2182         int spellingRangeEndOffset = spellingParagraph.checkingEnd() + offsetDueToReplacement;
   2183         const TextCheckingResult* result = &results[i];
   2184         int resultLocation = result->location + offsetDueToReplacement;
   2185         int resultLength = result->length;
   2186         bool resultEndsAtAmbiguousBoundary = ambiguousBoundaryOffset >= 0 && resultLocation + resultLength == ambiguousBoundaryOffset;
   2187 
   2188         // Only mark misspelling if:
   2189         // 1. Current text checking isn't done for autocorrection, in which case shouldMarkSpelling is false.
   2190         // 2. Result falls within spellingRange.
   2191         // 3. The word in question doesn't end at an ambiguous boundary. For instance, we would not mark
   2192         //    "wouldn'" as misspelled right after apostrophe is typed.
   2193         if (shouldMarkSpelling && result->type == TextCheckingTypeSpelling && resultLocation >= spellingParagraph.checkingStart() && resultLocation + resultLength <= spellingRangeEndOffset && !resultEndsAtAmbiguousBoundary) {
   2194             ASSERT(resultLength > 0 && resultLocation >= 0);
   2195             RefPtr<Range> misspellingRange = spellingParagraph.subrange(resultLocation, resultLength);
   2196             if (!m_spellingCorrector->isSpellingMarkerAllowed(misspellingRange))
   2197                 continue;
   2198             misspellingRange->startContainer(ec)->document()->markers()->addMarker(misspellingRange.get(), DocumentMarker::Spelling);
   2199         } else if (shouldMarkGrammar && result->type == TextCheckingTypeGrammar && grammarParagraph.checkingRangeCovers(resultLocation, resultLength)) {
   2200             ASSERT(resultLength > 0 && resultLocation >= 0);
   2201             for (unsigned j = 0; j < result->details.size(); j++) {
   2202                 const GrammarDetail* detail = &result->details[j];
   2203                 ASSERT(detail->length > 0 && detail->location >= 0);
   2204                 if (grammarParagraph.checkingRangeCovers(resultLocation + detail->location, detail->length)) {
   2205                     RefPtr<Range> badGrammarRange = grammarParagraph.subrange(resultLocation + detail->location, detail->length);
   2206                     grammarRange->startContainer(ec)->document()->markers()->addMarker(badGrammarRange.get(), DocumentMarker::Grammar, detail->userDescription);
   2207                 }
   2208             }
   2209         } else if (resultLocation + resultLength <= spellingRangeEndOffset && resultLocation + resultLength >= spellingParagraph.checkingStart()
   2210                     && (result->type == TextCheckingTypeLink
   2211                     || result->type == TextCheckingTypeQuote
   2212                     || result->type == TextCheckingTypeDash
   2213                     || result->type == TextCheckingTypeReplacement
   2214                     || result->type == TextCheckingTypeCorrection)) {
   2215             // In this case the result range just has to touch the spelling range, so we can handle replacing non-word text such as punctuation.
   2216             ASSERT(resultLength > 0 && resultLocation >= 0);
   2217 
   2218             if (shouldShowCorrectionPanel && (resultLocation + resultLength < spellingRangeEndOffset || result->type != TextCheckingTypeCorrection))
   2219                 continue;
   2220 
   2221             int replacementLength = result->replacement.length();
   2222 
   2223             // Apply replacement if:
   2224             // 1. The replacement length is non-zero.
   2225             // 2. The result doesn't end at an ambiguous boundary.
   2226             //    (FIXME: this is required until 6853027 is fixed and text checking can do this for us
   2227             bool doReplacement = replacementLength > 0 && !resultEndsAtAmbiguousBoundary;
   2228             RefPtr<Range> rangeToReplace = spellingParagraph.subrange(resultLocation, resultLength);
   2229             VisibleSelection selectionToReplace(rangeToReplace.get(), DOWNSTREAM);
   2230 
   2231             // adding links should be done only immediately after they are typed
   2232             if (result->type == TextCheckingTypeLink && selectionOffset > resultLocation + resultLength + 1)
   2233                 continue;
   2234 
   2235             String replacedString;
   2236 
   2237             // Don't correct spelling in an already-corrected word.
   2238             if (result->type == TextCheckingTypeCorrection) {
   2239                 replacedString = plainText(rangeToReplace.get());
   2240                 DocumentMarkerController* markers = m_frame->document()->markers();
   2241                 if (markers->hasMarkers(rangeToReplace.get(), DocumentMarker::Replacement)) {
   2242                     doReplacement = false;
   2243                     m_spellingCorrector->recordSpellcheckerResponseForModifiedCorrection(rangeToReplace.get(), replacedString, result->replacement);
   2244                 } else if (markers->hasMarkers(rangeToReplace.get(), DocumentMarker::RejectedCorrection))
   2245                     doReplacement = false;
   2246             }
   2247 
   2248             if (!(shouldPerformReplacement || shouldShowCorrectionPanel) || !doReplacement)
   2249                 continue;
   2250 
   2251             if (shouldShowCorrectionPanel) {
   2252                 ASSERT(SUPPORT_AUTOCORRECTION_PANEL);
   2253                 // shouldShowCorrectionPanel can be true only when the panel is available.
   2254                 if (resultLocation + resultLength == spellingRangeEndOffset) {
   2255                     // We only show the correction panel on the last word.
   2256                     m_spellingCorrector->show(rangeToReplace, result->replacement);
   2257                     break;
   2258                 }
   2259                 // If this function is called for showing correction panel, we ignore other correction or replacement.
   2260                 continue;
   2261             }
   2262 
   2263             if (selectionToReplace != m_frame->selection()->selection()) {
   2264                 if (!m_frame->selection()->shouldChangeSelection(selectionToReplace))
   2265                     continue;
   2266             }
   2267 
   2268             if (result->type == TextCheckingTypeLink) {
   2269                 m_frame->selection()->setSelection(selectionToReplace);
   2270                 selectionChanged = true;
   2271                 restoreSelectionAfterChange = false;
   2272                 if (canEditRichly())
   2273                     applyCommand(CreateLinkCommand::create(m_frame->document(), result->replacement));
   2274             } else if (canEdit() && shouldInsertText(result->replacement, rangeToReplace.get(), EditorInsertActionTyped)) {
   2275                 if (result->type == TextCheckingTypeCorrection)
   2276                     applyCommand(SpellingCorrectionCommand::create(rangeToReplace, result->replacement));
   2277                 else {
   2278                     m_frame->selection()->setSelection(selectionToReplace);
   2279                     replaceSelectionWithText(result->replacement, false, false);
   2280                 }
   2281 
   2282                 if (AXObjectCache::accessibilityEnabled()) {
   2283                     if (Element* root = m_frame->selection()->selection().rootEditableElement())
   2284                         m_frame->document()->axObjectCache()->postNotification(root->renderer(), AXObjectCache::AXAutocorrectionOccured, true);
   2285                 }
   2286 
   2287                 selectionChanged = true;
   2288                 offsetDueToReplacement += replacementLength - resultLength;
   2289                 if (resultLocation < selectionOffset) {
   2290                     selectionOffset += replacementLength - resultLength;
   2291                     if (ambiguousBoundaryOffset >= 0)
   2292                         ambiguousBoundaryOffset = selectionOffset - 1;
   2293                 }
   2294 
   2295                 // Add a marker so that corrections can easily be undone and won't be re-corrected.
   2296                 if (result->type == TextCheckingTypeCorrection)
   2297                     m_spellingCorrector->markCorrection(spellingParagraph.subrange(resultLocation, replacementLength), replacedString);
   2298             }
   2299         }
   2300     }
   2301 
   2302     if (selectionChanged) {
   2303         // Restore the caret position if we have made any replacements
   2304         spellingParagraph.expandRangeToNextEnd();
   2305         if (restoreSelectionAfterChange && selectionOffset >= 0 && selectionOffset <= spellingParagraph.rangeLength()) {
   2306             RefPtr<Range> selectionRange = spellingParagraph.subrange(0, selectionOffset);
   2307             m_frame->selection()->moveTo(selectionRange->endPosition(), DOWNSTREAM);
   2308             if (adjustSelectionForParagraphBoundaries)
   2309                 m_frame->selection()->modify(SelectionController::AlterationMove, DirectionForward, CharacterGranularity);
   2310         } else {
   2311             // If this fails for any reason, the fallback is to go one position beyond the last replacement
   2312             m_frame->selection()->moveTo(m_frame->selection()->end());
   2313             m_frame->selection()->modify(SelectionController::AlterationMove, DirectionForward, CharacterGranularity);
   2314         }
   2315     }
   2316 #else
   2317     ASSERT_NOT_REACHED();
   2318     UNUSED_PARAM(textCheckingOptions);
   2319     UNUSED_PARAM(spellingRange);
   2320     UNUSED_PARAM(grammarRange);
   2321 #endif // USE(UNIFIED_TEXT_CHECKING)
   2322 }
   2323 
   2324 void Editor::changeBackToReplacedString(const String& replacedString)
   2325 {
   2326 #if USE(UNIFIED_TEXT_CHECKING)
   2327     if (replacedString.isEmpty())
   2328         return;
   2329 
   2330     RefPtr<Range> selection = selectedRange();
   2331     if (!shouldInsertText(replacedString, selection.get(), EditorInsertActionPasted))
   2332         return;
   2333 
   2334     m_spellingCorrector->recordAutocorrectionResponseReversed(replacedString, selection);
   2335     TextCheckingParagraph paragraph(selection);
   2336     replaceSelectionWithText(replacedString, false, false);
   2337     RefPtr<Range> changedRange = paragraph.subrange(paragraph.checkingStart(), replacedString.length());
   2338     changedRange->startContainer()->document()->markers()->addMarker(changedRange.get(), DocumentMarker::Replacement, String());
   2339     m_spellingCorrector->markReversed(changedRange.get());
   2340 #else
   2341     ASSERT_NOT_REACHED();
   2342     UNUSED_PARAM(replacedString);
   2343 #endif // USE(UNIFIED_TEXT_CHECKING)
   2344 }
   2345 
   2346 
   2347 void Editor::markMisspellingsAndBadGrammar(const VisibleSelection& spellingSelection, bool markGrammar, const VisibleSelection& grammarSelection)
   2348 {
   2349 #if USE(UNIFIED_TEXT_CHECKING)
   2350     if (!isContinuousSpellCheckingEnabled())
   2351         return;
   2352     TextCheckingOptions textCheckingOptions = MarkSpelling | CheckForCorrection;
   2353     if (markGrammar && isGrammarCheckingEnabled())
   2354         textCheckingOptions |= MarkGrammar;
   2355     markAllMisspellingsAndBadGrammarInRanges(textCheckingOptions, spellingSelection.toNormalizedRange().get(), grammarSelection.toNormalizedRange().get());
   2356 #else
   2357     RefPtr<Range> firstMisspellingRange;
   2358     markMisspellings(spellingSelection, firstMisspellingRange);
   2359     if (markGrammar)
   2360         markBadGrammar(grammarSelection);
   2361 #endif
   2362 }
   2363 
   2364 void Editor::unappliedSpellCorrection(const VisibleSelection& selectionOfCorrected, const String& corrected, const String& correction)
   2365 {
   2366     m_spellingCorrector->respondToUnappliedSpellCorrection(selectionOfCorrected, corrected, correction);
   2367 }
   2368 
   2369 void Editor::updateMarkersForWordsAffectedByEditing(bool doNotRemoveIfSelectionAtWordBoundary)
   2370 {
   2371     if (!m_spellingCorrector->shouldRemoveMarkersUponEditing())
   2372         return;
   2373 
   2374     // We want to remove the markers from a word if an editing command will change the word. This can happen in one of
   2375     // several scenarios:
   2376     // 1. Insert in the middle of a word.
   2377     // 2. Appending non whitespace at the beginning of word.
   2378     // 3. Appending non whitespace at the end of word.
   2379     // Note that, appending only whitespaces at the beginning or end of word won't change the word, so we don't need to
   2380     // remove the markers on that word.
   2381     // Of course, if current selection is a range, we potentially will edit two words that fall on the boundaries of
   2382     // selection, and remove words between the selection boundaries.
   2383     //
   2384     VisiblePosition startOfSelection = frame()->selection()->selection().start();
   2385     VisiblePosition endOfSelection = frame()->selection()->selection().end();
   2386     if (startOfSelection.isNull())
   2387         return;
   2388     // First word is the word that ends after or on the start of selection.
   2389     VisiblePosition startOfFirstWord = startOfWord(startOfSelection, LeftWordIfOnBoundary);
   2390     VisiblePosition endOfFirstWord = endOfWord(startOfSelection, LeftWordIfOnBoundary);
   2391     // Last word is the word that begins before or on the end of selection
   2392     VisiblePosition startOfLastWord = startOfWord(endOfSelection, RightWordIfOnBoundary);
   2393     VisiblePosition endOfLastWord = endOfWord(endOfSelection, RightWordIfOnBoundary);
   2394 
   2395     if (startOfFirstWord.isNull()) {
   2396         startOfFirstWord = startOfWord(startOfSelection, RightWordIfOnBoundary);
   2397         endOfFirstWord = endOfWord(startOfSelection, RightWordIfOnBoundary);
   2398     }
   2399 
   2400     if (endOfLastWord.isNull()) {
   2401         startOfLastWord = startOfWord(endOfSelection, LeftWordIfOnBoundary);
   2402         endOfLastWord = endOfWord(endOfSelection, LeftWordIfOnBoundary);
   2403     }
   2404 
   2405     // If doNotRemoveIfSelectionAtWordBoundary is true, and first word ends at the start of selection,
   2406     // we choose next word as the first word.
   2407     if (doNotRemoveIfSelectionAtWordBoundary && endOfFirstWord == startOfSelection) {
   2408         startOfFirstWord = nextWordPosition(startOfFirstWord);
   2409         endOfFirstWord = endOfWord(startOfFirstWord, RightWordIfOnBoundary);
   2410         if (startOfFirstWord == endOfSelection)
   2411             return;
   2412     }
   2413 
   2414     // If doNotRemoveIfSelectionAtWordBoundary is true, and last word begins at the end of selection,
   2415     // we choose previous word as the last word.
   2416     if (doNotRemoveIfSelectionAtWordBoundary && startOfLastWord == endOfSelection) {
   2417         startOfLastWord = previousWordPosition(startOfLastWord);
   2418         endOfLastWord = endOfWord(startOfLastWord, RightWordIfOnBoundary);
   2419         if (endOfLastWord == startOfSelection)
   2420             return;
   2421     }
   2422 
   2423     if (startOfFirstWord.isNull() || endOfFirstWord.isNull() || startOfLastWord.isNull() || endOfLastWord.isNull())
   2424         return;
   2425 
   2426     // Now we remove markers on everything between startOfFirstWord and endOfLastWord.
   2427     // However, if an autocorrection change a single word to multiple words, we want to remove correction mark from all the
   2428     // resulted words even we only edit one of them. For example, assuming autocorrection changes "avantgarde" to "avant
   2429     // garde", we will have CorrectionIndicator marker on both words and on the whitespace between them. If we then edit garde,
   2430     // we would like to remove the marker from word "avant" and whitespace as well. So we need to get the continous range of
   2431     // of marker that contains the word in question, and remove marker on that whole range.
   2432     Document* document = m_frame->document();
   2433     RefPtr<Range> wordRange = Range::create(document, startOfFirstWord.deepEquivalent(), endOfLastWord.deepEquivalent());
   2434 
   2435     document->markers()->removeMarkers(wordRange.get(), DocumentMarker::Spelling | DocumentMarker::CorrectionIndicator | DocumentMarker::SpellCheckingExemption, DocumentMarkerController::RemovePartiallyOverlappingMarker);
   2436     document->markers()->clearDescriptionOnMarkersIntersectingRange(wordRange.get(), DocumentMarker::Replacement);
   2437 }
   2438 
   2439 PassRefPtr<Range> Editor::rangeForPoint(const IntPoint& windowPoint)
   2440 {
   2441     Document* document = m_frame->documentAtPoint(windowPoint);
   2442     if (!document)
   2443         return 0;
   2444 
   2445     Frame* frame = document->frame();
   2446     ASSERT(frame);
   2447     FrameView* frameView = frame->view();
   2448     if (!frameView)
   2449         return 0;
   2450     IntPoint framePoint = frameView->windowToContents(windowPoint);
   2451     VisibleSelection selection(frame->visiblePositionForPoint(framePoint));
   2452     return avoidIntersectionWithNode(selection.toNormalizedRange().get(), m_deleteButtonController->containerElement());
   2453 }
   2454 
   2455 void Editor::revealSelectionAfterEditingOperation()
   2456 {
   2457     if (m_ignoreCompositionSelectionChange)
   2458         return;
   2459 
   2460     m_frame->selection()->revealSelection(ScrollAlignment::alignToEdgeIfNeeded);
   2461 }
   2462 
   2463 void Editor::setIgnoreCompositionSelectionChange(bool ignore)
   2464 {
   2465     if (m_ignoreCompositionSelectionChange == ignore)
   2466         return;
   2467 
   2468     m_ignoreCompositionSelectionChange = ignore;
   2469     if (!ignore)
   2470         revealSelectionAfterEditingOperation();
   2471 }
   2472 
   2473 PassRefPtr<Range> Editor::compositionRange() const
   2474 {
   2475     if (!m_compositionNode)
   2476         return 0;
   2477     unsigned length = m_compositionNode->length();
   2478     unsigned start = min(m_compositionStart, length);
   2479     unsigned end = min(max(start, m_compositionEnd), length);
   2480     if (start >= end)
   2481         return 0;
   2482     return Range::create(m_compositionNode->document(), m_compositionNode.get(), start, m_compositionNode.get(), end);
   2483 }
   2484 
   2485 bool Editor::getCompositionSelection(unsigned& selectionStart, unsigned& selectionEnd) const
   2486 {
   2487     if (!m_compositionNode)
   2488         return false;
   2489     Position start = m_frame->selection()->start();
   2490     if (start.deprecatedNode() != m_compositionNode)
   2491         return false;
   2492     Position end = m_frame->selection()->end();
   2493     if (end.deprecatedNode() != m_compositionNode)
   2494         return false;
   2495 
   2496     if (static_cast<unsigned>(start.deprecatedEditingOffset()) < m_compositionStart)
   2497         return false;
   2498     if (static_cast<unsigned>(end.deprecatedEditingOffset()) > m_compositionEnd)
   2499         return false;
   2500 
   2501     selectionStart = start.deprecatedEditingOffset() - m_compositionStart;
   2502     selectionEnd = start.deprecatedEditingOffset() - m_compositionEnd;
   2503     return true;
   2504 }
   2505 
   2506 void Editor::transpose()
   2507 {
   2508     if (!canEdit())
   2509         return;
   2510 
   2511      VisibleSelection selection = m_frame->selection()->selection();
   2512      if (!selection.isCaret())
   2513          return;
   2514 
   2515     // Make a selection that goes back one character and forward two characters.
   2516     VisiblePosition caret = selection.visibleStart();
   2517     VisiblePosition next = isEndOfParagraph(caret) ? caret : caret.next();
   2518     VisiblePosition previous = next.previous();
   2519     if (next == previous)
   2520         return;
   2521     previous = previous.previous();
   2522     if (!inSameParagraph(next, previous))
   2523         return;
   2524     RefPtr<Range> range = makeRange(previous, next);
   2525     if (!range)
   2526         return;
   2527     VisibleSelection newSelection(range.get(), DOWNSTREAM);
   2528 
   2529     // Transpose the two characters.
   2530     String text = plainText(range.get());
   2531     if (text.length() != 2)
   2532         return;
   2533     String transposed = text.right(1) + text.left(1);
   2534 
   2535     // Select the two characters.
   2536     if (newSelection != m_frame->selection()->selection()) {
   2537         if (!m_frame->selection()->shouldChangeSelection(newSelection))
   2538             return;
   2539         m_frame->selection()->setSelection(newSelection);
   2540     }
   2541 
   2542     // Insert the transposed characters.
   2543     if (!shouldInsertText(transposed, range.get(), EditorInsertActionTyped))
   2544         return;
   2545     replaceSelectionWithText(transposed, false, false);
   2546 }
   2547 
   2548 void Editor::addToKillRing(Range* range, bool prepend)
   2549 {
   2550     if (m_shouldStartNewKillRingSequence)
   2551         killRing()->startNewSequence();
   2552 
   2553     String text = plainText(range);
   2554     if (prepend)
   2555         killRing()->prepend(text);
   2556     else
   2557         killRing()->append(text);
   2558     m_shouldStartNewKillRingSequence = false;
   2559 }
   2560 
   2561 void Editor::startCorrectionPanelTimer()
   2562 {
   2563     m_spellingCorrector->startCorrectionPanelTimer(CorrectionPanelInfo::PanelTypeCorrection);
   2564 }
   2565 
   2566 void Editor::handleCorrectionPanelResult(const String& correction)
   2567 {
   2568     m_spellingCorrector->handleCorrectionPanelResult(correction);
   2569 }
   2570 
   2571 
   2572 void Editor::dismissCorrectionPanelAsIgnored()
   2573 {
   2574     m_spellingCorrector->dismiss(ReasonForDismissingCorrectionPanelIgnored);
   2575 }
   2576 
   2577 bool Editor::insideVisibleArea(const IntPoint& point) const
   2578 {
   2579     if (m_frame->excludeFromTextSearch())
   2580         return false;
   2581 
   2582     // Right now, we only check the visibility of a point for disconnected frames. For all other
   2583     // frames, we assume visibility.
   2584     Frame* frame = m_frame->isDisconnected() ? m_frame : m_frame->tree()->top(true);
   2585     if (!frame->isDisconnected())
   2586         return true;
   2587 
   2588     RenderPart* renderer = frame->ownerRenderer();
   2589     if (!renderer)
   2590         return false;
   2591 
   2592     RenderBlock* container = renderer->containingBlock();
   2593     if (!(container->style()->overflowX() == OHIDDEN || container->style()->overflowY() == OHIDDEN))
   2594         return true;
   2595 
   2596     IntRect rectInPageCoords = container->overflowClipRect(0, 0);
   2597     IntRect rectInFrameCoords = IntRect(renderer->x() * -1, renderer->y() * -1,
   2598                                     rectInPageCoords.width(), rectInPageCoords.height());
   2599 
   2600     return rectInFrameCoords.contains(point);
   2601 }
   2602 
   2603 bool Editor::insideVisibleArea(Range* range) const
   2604 {
   2605     if (!range)
   2606         return true;
   2607 
   2608     if (m_frame->excludeFromTextSearch())
   2609         return false;
   2610 
   2611     // Right now, we only check the visibility of a range for disconnected frames. For all other
   2612     // frames, we assume visibility.
   2613     Frame* frame = m_frame->isDisconnected() ? m_frame : m_frame->tree()->top(true);
   2614     if (!frame->isDisconnected())
   2615         return true;
   2616 
   2617     RenderPart* renderer = frame->ownerRenderer();
   2618     if (!renderer)
   2619         return false;
   2620 
   2621     RenderBlock* container = renderer->containingBlock();
   2622     if (!(container->style()->overflowX() == OHIDDEN || container->style()->overflowY() == OHIDDEN))
   2623         return true;
   2624 
   2625     IntRect rectInPageCoords = container->overflowClipRect(0, 0);
   2626     IntRect rectInFrameCoords = IntRect(renderer->x() * -1, renderer->y() * -1,
   2627                                     rectInPageCoords.width(), rectInPageCoords.height());
   2628     IntRect resultRect = range->boundingBox();
   2629 
   2630     return rectInFrameCoords.contains(resultRect);
   2631 }
   2632 
   2633 PassRefPtr<Range> Editor::firstVisibleRange(const String& target, FindOptions options)
   2634 {
   2635     RefPtr<Range> searchRange(rangeOfContents(m_frame->document()));
   2636     RefPtr<Range> resultRange = findPlainText(searchRange.get(), target, options & ~Backwards);
   2637     ExceptionCode ec = 0;
   2638 
   2639     while (!insideVisibleArea(resultRange.get())) {
   2640         searchRange->setStartAfter(resultRange->endContainer(), ec);
   2641         if (searchRange->startContainer() == searchRange->endContainer())
   2642             return Range::create(m_frame->document());
   2643         resultRange = findPlainText(searchRange.get(), target, options & ~Backwards);
   2644     }
   2645 
   2646     return resultRange;
   2647 }
   2648 
   2649 PassRefPtr<Range> Editor::lastVisibleRange(const String& target, FindOptions options)
   2650 {
   2651     RefPtr<Range> searchRange(rangeOfContents(m_frame->document()));
   2652     RefPtr<Range> resultRange = findPlainText(searchRange.get(), target, options | Backwards);
   2653     ExceptionCode ec = 0;
   2654 
   2655     while (!insideVisibleArea(resultRange.get())) {
   2656         searchRange->setEndBefore(resultRange->startContainer(), ec);
   2657         if (searchRange->startContainer() == searchRange->endContainer())
   2658             return Range::create(m_frame->document());
   2659         resultRange = findPlainText(searchRange.get(), target, options | Backwards);
   2660     }
   2661 
   2662     return resultRange;
   2663 }
   2664 
   2665 PassRefPtr<Range> Editor::nextVisibleRange(Range* currentRange, const String& target, FindOptions options)
   2666 {
   2667     if (m_frame->excludeFromTextSearch())
   2668         return Range::create(m_frame->document());
   2669 
   2670     RefPtr<Range> resultRange = currentRange;
   2671     RefPtr<Range> searchRange(rangeOfContents(m_frame->document()));
   2672     ExceptionCode ec = 0;
   2673     bool forward = !(options & Backwards);
   2674     for ( ; !insideVisibleArea(resultRange.get()); resultRange = findPlainText(searchRange.get(), target, options)) {
   2675         if (resultRange->collapsed(ec)) {
   2676             if (!resultRange->startContainer()->isInShadowTree())
   2677                 break;
   2678             searchRange = rangeOfContents(m_frame->document());
   2679             if (forward)
   2680                 searchRange->setStartAfter(resultRange->startContainer()->shadowAncestorNode(), ec);
   2681             else
   2682                 searchRange->setEndBefore(resultRange->startContainer()->shadowAncestorNode(), ec);
   2683             continue;
   2684         }
   2685 
   2686         if (forward)
   2687             searchRange->setStartAfter(resultRange->endContainer(), ec);
   2688         else
   2689             searchRange->setEndBefore(resultRange->startContainer(), ec);
   2690 
   2691         Node* shadowTreeRoot = searchRange->shadowTreeRootNode();
   2692         if (searchRange->collapsed(ec) && shadowTreeRoot) {
   2693             if (forward)
   2694                 searchRange->setEnd(shadowTreeRoot, shadowTreeRoot->childNodeCount(), ec);
   2695             else
   2696                 searchRange->setStartBefore(shadowTreeRoot, ec);
   2697         }
   2698 
   2699         if (searchRange->startContainer()->isDocumentNode() && searchRange->endContainer()->isDocumentNode())
   2700             break;
   2701     }
   2702 
   2703     if (insideVisibleArea(resultRange.get()))
   2704         return resultRange;
   2705 
   2706     if (!(options & WrapAround))
   2707         return Range::create(m_frame->document());
   2708 
   2709     if (options & Backwards)
   2710         return lastVisibleRange(target, options);
   2711 
   2712     return firstVisibleRange(target, options);
   2713 }
   2714 
   2715 void Editor::changeSelectionAfterCommand(const VisibleSelection& newSelection, bool closeTyping, bool clearTypingStyle)
   2716 {
   2717     // If the new selection is orphaned, then don't update the selection.
   2718     if (newSelection.start().isOrphan() || newSelection.end().isOrphan())
   2719         return;
   2720 
   2721     // If there is no selection change, don't bother sending shouldChangeSelection, but still call setSelection,
   2722     // because there is work that it must do in this situation.
   2723     // The old selection can be invalid here and calling shouldChangeSelection can produce some strange calls.
   2724     // See <rdar://problem/5729315> Some shouldChangeSelectedDOMRange contain Ranges for selections that are no longer valid
   2725     bool selectionDidNotChangeDOMPosition = newSelection == m_frame->selection()->selection();
   2726     if (selectionDidNotChangeDOMPosition || m_frame->selection()->shouldChangeSelection(newSelection)) {
   2727         SelectionController::SetSelectionOptions options = 0;
   2728         if (closeTyping)
   2729             options |= SelectionController::CloseTyping;
   2730         if (clearTypingStyle)
   2731             options |= SelectionController::ClearTypingStyle;
   2732         m_frame->selection()->setSelection(newSelection, options);
   2733     }
   2734 
   2735     // Some editing operations change the selection visually without affecting its position within the DOM.
   2736     // For example when you press return in the following (the caret is marked by ^):
   2737     // <div contentEditable="true"><div>^Hello</div></div>
   2738     // WebCore inserts <div><br></div> *before* the current block, which correctly moves the paragraph down but which doesn't
   2739     // change the caret's DOM position (["hello", 0]).  In these situations the above SelectionController::setSelection call
   2740     // does not call EditorClient::respondToChangedSelection(), which, on the Mac, sends selection change notifications and
   2741     // starts a new kill ring sequence, but we want to do these things (matches AppKit).
   2742     if (selectionDidNotChangeDOMPosition)
   2743         client()->respondToChangedSelection();
   2744 }
   2745 
   2746 String Editor::selectedText() const
   2747 {
   2748     // We remove '\0' characters because they are not visibly rendered to the user.
   2749     return plainText(m_frame->selection()->toNormalizedRange().get()).replace(0, "");
   2750 }
   2751 
   2752 IntRect Editor::firstRectForRange(Range* range) const
   2753 {
   2754     int extraWidthToEndOfLine = 0;
   2755     ASSERT(range->startContainer());
   2756     ASSERT(range->endContainer());
   2757 
   2758     InlineBox* startInlineBox;
   2759     int startCaretOffset;
   2760     Position startPosition = VisiblePosition(range->startPosition()).deepEquivalent();
   2761     if (startPosition.isNull())
   2762         return IntRect();
   2763     startPosition.getInlineBoxAndOffset(DOWNSTREAM, startInlineBox, startCaretOffset);
   2764 
   2765     RenderObject* startRenderer = startPosition.deprecatedNode()->renderer();
   2766     ASSERT(startRenderer);
   2767     IntRect startCaretRect = startRenderer->localCaretRect(startInlineBox, startCaretOffset, &extraWidthToEndOfLine);
   2768     if (startCaretRect != IntRect())
   2769         startCaretRect = startRenderer->localToAbsoluteQuad(FloatRect(startCaretRect)).enclosingBoundingBox();
   2770 
   2771     InlineBox* endInlineBox;
   2772     int endCaretOffset;
   2773     Position endPosition = VisiblePosition(range->endPosition()).deepEquivalent();
   2774     if (endPosition.isNull())
   2775         return IntRect();
   2776     endPosition.getInlineBoxAndOffset(UPSTREAM, endInlineBox, endCaretOffset);
   2777 
   2778     RenderObject* endRenderer = endPosition.deprecatedNode()->renderer();
   2779     ASSERT(endRenderer);
   2780     IntRect endCaretRect = endRenderer->localCaretRect(endInlineBox, endCaretOffset);
   2781     if (endCaretRect != IntRect())
   2782         endCaretRect = endRenderer->localToAbsoluteQuad(FloatRect(endCaretRect)).enclosingBoundingBox();
   2783 
   2784     if (startCaretRect.y() == endCaretRect.y()) {
   2785         // start and end are on the same line
   2786         return IntRect(min(startCaretRect.x(), endCaretRect.x()),
   2787             startCaretRect.y(),
   2788             abs(endCaretRect.x() - startCaretRect.x()),
   2789             max(startCaretRect.height(), endCaretRect.height()));
   2790     }
   2791 
   2792     // start and end aren't on the same line, so go from start to the end of its line
   2793     return IntRect(startCaretRect.x(),
   2794         startCaretRect.y(),
   2795         startCaretRect.width() + extraWidthToEndOfLine,
   2796         startCaretRect.height());
   2797 }
   2798 
   2799 bool Editor::shouldChangeSelection(const VisibleSelection& oldSelection, const VisibleSelection& newSelection, EAffinity affinity, bool stillSelecting) const
   2800 {
   2801     return client()->shouldChangeSelectedRange(oldSelection.toNormalizedRange().get(), newSelection.toNormalizedRange().get(), affinity, stillSelecting);
   2802 }
   2803 
   2804 void Editor::computeAndSetTypingStyle(CSSStyleDeclaration* style, EditAction editingAction)
   2805 {
   2806     if (!style || !style->length()) {
   2807         m_frame->selection()->clearTypingStyle();
   2808         return;
   2809     }
   2810 
   2811     // Calculate the current typing style.
   2812     RefPtr<EditingStyle> typingStyle;
   2813     if (m_frame->selection()->typingStyle()) {
   2814         typingStyle = m_frame->selection()->typingStyle()->copy();
   2815         typingStyle->overrideWithStyle(style->makeMutable().get());
   2816     } else
   2817         typingStyle = EditingStyle::create(style);
   2818 
   2819     typingStyle->prepareToApplyAt(m_frame->selection()->selection().visibleStart().deepEquivalent(), EditingStyle::PreserveWritingDirection);
   2820 
   2821     // Handle block styles, substracting these from the typing style.
   2822     RefPtr<EditingStyle> blockStyle = typingStyle->extractAndRemoveBlockProperties();
   2823     if (!blockStyle->isEmpty())
   2824         applyCommand(ApplyStyleCommand::create(m_frame->document(), blockStyle.get(), editingAction));
   2825 
   2826     // Set the remaining style as the typing style.
   2827     m_frame->selection()->setTypingStyle(typingStyle);
   2828 }
   2829 
   2830 PassRefPtr<EditingStyle> Editor::selectionStartStyle() const
   2831 {
   2832     if (m_frame->selection()->isNone())
   2833         return 0;
   2834 
   2835     RefPtr<Range> range(m_frame->selection()->toNormalizedRange());
   2836     Position position = range->editingStartPosition();
   2837 
   2838     // If the pos is at the end of a text node, then this node is not fully selected.
   2839     // Move it to the next deep equivalent position to avoid removing the style from this node.
   2840     // e.g. if pos was at Position("hello", 5) in <b>hello<div>world</div></b>, we want Position("world", 0) instead.
   2841     // We only do this for range because caret at Position("hello", 5) in <b>hello</b>world should give you font-weight: bold.
   2842     Node* positionNode = position.containerNode();
   2843     if (m_frame->selection()->isRange() && positionNode && positionNode->isTextNode() && position.computeOffsetInContainerNode() == positionNode->maxCharacterOffset())
   2844         position = nextVisuallyDistinctCandidate(position);
   2845 
   2846     Element* element = position.element();
   2847     if (!element)
   2848         return 0;
   2849 
   2850     RefPtr<EditingStyle> style = EditingStyle::create(element, EditingStyle::AllProperties);
   2851     style->mergeTypingStyle(m_frame->document());
   2852     return style;
   2853 }
   2854 
   2855 void Editor::textFieldDidBeginEditing(Element* e)
   2856 {
   2857     if (client())
   2858         client()->textFieldDidBeginEditing(e);
   2859 }
   2860 
   2861 void Editor::textFieldDidEndEditing(Element* e)
   2862 {
   2863     if (client())
   2864         client()->textFieldDidEndEditing(e);
   2865 }
   2866 
   2867 void Editor::textDidChangeInTextField(Element* e)
   2868 {
   2869     if (client())
   2870         client()->textDidChangeInTextField(e);
   2871 }
   2872 
   2873 bool Editor::doTextFieldCommandFromEvent(Element* e, KeyboardEvent* ke)
   2874 {
   2875     if (client())
   2876         return client()->doTextFieldCommandFromEvent(e, ke);
   2877 
   2878     return false;
   2879 }
   2880 
   2881 void Editor::textWillBeDeletedInTextField(Element* input)
   2882 {
   2883     if (client())
   2884         client()->textWillBeDeletedInTextField(input);
   2885 }
   2886 
   2887 void Editor::textDidChangeInTextArea(Element* e)
   2888 {
   2889     if (client())
   2890         client()->textDidChangeInTextArea(e);
   2891 }
   2892 
   2893 void Editor::applyEditingStyleToBodyElement() const
   2894 {
   2895     RefPtr<NodeList> list = m_frame->document()->getElementsByTagName("body");
   2896     unsigned len = list->length();
   2897     for (unsigned i = 0; i < len; i++)
   2898         applyEditingStyleToElement(static_cast<Element*>(list->item(i)));
   2899 }
   2900 
   2901 void Editor::applyEditingStyleToElement(Element* element) const
   2902 {
   2903     if (!element)
   2904         return;
   2905 
   2906     CSSStyleDeclaration* style = element->style();
   2907     ASSERT(style);
   2908 
   2909     ExceptionCode ec = 0;
   2910     style->setProperty(CSSPropertyWordWrap, "break-word", false, ec);
   2911     ASSERT(!ec);
   2912     style->setProperty(CSSPropertyWebkitNbspMode, "space", false, ec);
   2913     ASSERT(!ec);
   2914     style->setProperty(CSSPropertyWebkitLineBreak, "after-white-space", false, ec);
   2915     ASSERT(!ec);
   2916 }
   2917 
   2918 RenderStyle* Editor::styleForSelectionStart(Node *&nodeToRemove) const
   2919 {
   2920     nodeToRemove = 0;
   2921 
   2922     if (m_frame->selection()->isNone())
   2923         return 0;
   2924 
   2925     Position position = m_frame->selection()->selection().visibleStart().deepEquivalent();
   2926     if (!position.isCandidate())
   2927         return 0;
   2928     if (!position.deprecatedNode())
   2929         return 0;
   2930 
   2931     RefPtr<EditingStyle> typingStyle = m_frame->selection()->typingStyle();
   2932     if (!typingStyle || !typingStyle->style())
   2933         return position.deprecatedNode()->renderer()->style();
   2934 
   2935     RefPtr<Element> styleElement = m_frame->document()->createElement(spanTag, false);
   2936 
   2937     ExceptionCode ec = 0;
   2938     String styleText = typingStyle->style()->cssText() + " display: inline";
   2939     styleElement->setAttribute(styleAttr, styleText.impl(), ec);
   2940     ASSERT(!ec);
   2941 
   2942     styleElement->appendChild(m_frame->document()->createEditingTextNode(""), ec);
   2943     ASSERT(!ec);
   2944 
   2945     position.deprecatedNode()->parentNode()->appendChild(styleElement, ec);
   2946     ASSERT(!ec);
   2947 
   2948     nodeToRemove = styleElement.get();
   2949     return styleElement->renderer() ? styleElement->renderer()->style() : 0;
   2950 }
   2951 
   2952 // Searches from the beginning of the document if nothing is selected.
   2953 bool Editor::findString(const String& target, bool forward, bool caseFlag, bool wrapFlag, bool startInSelection)
   2954 {
   2955     FindOptions options = (forward ? 0 : Backwards) | (caseFlag ? 0 : CaseInsensitive) | (wrapFlag ? WrapAround : 0) | (startInSelection ? StartInSelection : 0);
   2956     return findString(target, options);
   2957 }
   2958 
   2959 bool Editor::findString(const String& target, FindOptions options)
   2960 {
   2961     if (target.isEmpty())
   2962         return false;
   2963 
   2964     if (m_frame->excludeFromTextSearch())
   2965         return false;
   2966 
   2967     // Start from an edge of the selection, if there's a selection that's not in shadow content. Which edge
   2968     // is used depends on whether we're searching forward or backward, and whether startInSelection is set.
   2969     RefPtr<Range> searchRange(rangeOfContents(m_frame->document()));
   2970     VisibleSelection selection = m_frame->selection()->selection();
   2971 
   2972     bool forward = !(options & Backwards);
   2973     bool startInSelection = options & StartInSelection;
   2974     if (forward)
   2975         setStart(searchRange.get(), startInSelection ? selection.visibleStart() : selection.visibleEnd());
   2976     else
   2977         setEnd(searchRange.get(), startInSelection ? selection.visibleEnd() : selection.visibleStart());
   2978 
   2979     RefPtr<Node> shadowTreeRoot = selection.shadowTreeRootNode();
   2980     if (shadowTreeRoot) {
   2981         ExceptionCode ec = 0;
   2982         if (forward)
   2983             searchRange->setEnd(shadowTreeRoot.get(), shadowTreeRoot->childNodeCount(), ec);
   2984         else
   2985             searchRange->setStart(shadowTreeRoot.get(), 0, ec);
   2986     }
   2987 
   2988     RefPtr<Range> resultRange(findPlainText(searchRange.get(), target, options));
   2989     // If we started in the selection and the found range exactly matches the existing selection, find again.
   2990     // Build a selection with the found range to remove collapsed whitespace.
   2991     // Compare ranges instead of selection objects to ignore the way that the current selection was made.
   2992     if (startInSelection && areRangesEqual(VisibleSelection(resultRange.get()).toNormalizedRange().get(), selection.toNormalizedRange().get())) {
   2993         searchRange = rangeOfContents(m_frame->document());
   2994         if (forward)
   2995             setStart(searchRange.get(), selection.visibleEnd());
   2996         else
   2997             setEnd(searchRange.get(), selection.visibleStart());
   2998 
   2999         if (shadowTreeRoot) {
   3000             ExceptionCode ec = 0;
   3001             if (forward)
   3002                 searchRange->setEnd(shadowTreeRoot.get(), shadowTreeRoot->childNodeCount(), ec);
   3003             else
   3004                 searchRange->setStart(shadowTreeRoot.get(), 0, ec);
   3005         }
   3006 
   3007         resultRange = findPlainText(searchRange.get(), target, options);
   3008     }
   3009 
   3010     ExceptionCode exception = 0;
   3011 
   3012     // If nothing was found in the shadow tree, search in main content following the shadow tree.
   3013     if (resultRange->collapsed(exception) && shadowTreeRoot) {
   3014         searchRange = rangeOfContents(m_frame->document());
   3015         if (forward)
   3016             searchRange->setStartAfter(shadowTreeRoot->shadowHost(), exception);
   3017         else
   3018             searchRange->setEndBefore(shadowTreeRoot->shadowHost(), exception);
   3019 
   3020         resultRange = findPlainText(searchRange.get(), target, options);
   3021     }
   3022 
   3023     if (!insideVisibleArea(resultRange.get())) {
   3024         resultRange = nextVisibleRange(resultRange.get(), target, options);
   3025         if (!resultRange)
   3026             return false;
   3027     }
   3028 
   3029     // If we didn't find anything and we're wrapping, search again in the entire document (this will
   3030     // redundantly re-search the area already searched in some cases).
   3031     if (resultRange->collapsed(exception) && options & WrapAround) {
   3032         searchRange = rangeOfContents(m_frame->document());
   3033         resultRange = findPlainText(searchRange.get(), target, options);
   3034         // We used to return false here if we ended up with the same range that we started with
   3035         // (e.g., the selection was already the only instance of this text). But we decided that
   3036         // this should be a success case instead, so we'll just fall through in that case.
   3037     }
   3038 
   3039     if (resultRange->collapsed(exception))
   3040         return false;
   3041 
   3042     m_frame->selection()->setSelection(VisibleSelection(resultRange.get(), DOWNSTREAM));
   3043     m_frame->selection()->revealSelection();
   3044     return true;
   3045 }
   3046 
   3047 static bool isFrameInRange(Frame* frame, Range* range)
   3048 {
   3049     bool inRange = false;
   3050     for (HTMLFrameOwnerElement* ownerElement = frame->ownerElement(); ownerElement; ownerElement = ownerElement->document()->ownerElement()) {
   3051         if (ownerElement->document() == range->ownerDocument()) {
   3052             ExceptionCode ec = 0;
   3053             inRange = range->intersectsNode(ownerElement, ec);
   3054             break;
   3055         }
   3056     }
   3057     return inRange;
   3058 }
   3059 
   3060 unsigned Editor::countMatchesForText(const String& target, FindOptions options, unsigned limit, bool markMatches)
   3061 {
   3062     return countMatchesForText(target, 0, options, limit, markMatches);
   3063 }
   3064 
   3065 unsigned Editor::countMatchesForText(const String& target, Range* range, FindOptions options, unsigned limit, bool markMatches)
   3066 {
   3067     if (target.isEmpty())
   3068         return 0;
   3069 
   3070     RefPtr<Range> searchRange;
   3071     if (range) {
   3072         if (range->ownerDocument() == m_frame->document())
   3073             searchRange = range;
   3074         else if (!isFrameInRange(m_frame, range))
   3075             return 0;
   3076     }
   3077     if (!searchRange)
   3078         searchRange = rangeOfContents(m_frame->document());
   3079 
   3080     Node* originalEndContainer = searchRange->endContainer();
   3081     int originalEndOffset = searchRange->endOffset();
   3082 
   3083     ExceptionCode exception = 0;
   3084     unsigned matchCount = 0;
   3085     do {
   3086         RefPtr<Range> resultRange(findPlainText(searchRange.get(), target, options & ~Backwards));
   3087         if (resultRange->collapsed(exception)) {
   3088             if (!resultRange->startContainer()->isInShadowTree())
   3089                 break;
   3090 
   3091             searchRange->setStartAfter(resultRange->startContainer()->shadowAncestorNode(), exception);
   3092             searchRange->setEnd(originalEndContainer, originalEndOffset, exception);
   3093             continue;
   3094         }
   3095 
   3096         // Only treat the result as a match if it is visible
   3097         if (insideVisibleArea(resultRange.get())) {
   3098             ++matchCount;
   3099             if (markMatches)
   3100                 m_frame->document()->markers()->addMarker(resultRange.get(), DocumentMarker::TextMatch);
   3101         }
   3102 
   3103         // Stop looking if we hit the specified limit. A limit of 0 means no limit.
   3104         if (limit > 0 && matchCount >= limit)
   3105             break;
   3106 
   3107         // Set the new start for the search range to be the end of the previous
   3108         // result range. There is no need to use a VisiblePosition here,
   3109         // since findPlainText will use a TextIterator to go over the visible
   3110         // text nodes.
   3111         searchRange->setStart(resultRange->endContainer(exception), resultRange->endOffset(exception), exception);
   3112 
   3113         Node* shadowTreeRoot = searchRange->shadowTreeRootNode();
   3114         if (searchRange->collapsed(exception) && shadowTreeRoot)
   3115             searchRange->setEnd(shadowTreeRoot, shadowTreeRoot->childNodeCount(), exception);
   3116     } while (true);
   3117 
   3118     if (markMatches) {
   3119         // Do a "fake" paint in order to execute the code that computes the rendered rect for each text match.
   3120         if (m_frame->view() && m_frame->contentRenderer()) {
   3121             m_frame->document()->updateLayout(); // Ensure layout is up to date.
   3122             IntRect visibleRect = m_frame->view()->visibleContentRect();
   3123             if (!visibleRect.isEmpty()) {
   3124                 GraphicsContext context((PlatformGraphicsContext*)0);
   3125                 context.setPaintingDisabled(true);
   3126 
   3127                 PaintBehavior oldBehavior = m_frame->view()->paintBehavior();
   3128                 m_frame->view()->setPaintBehavior(oldBehavior | PaintBehaviorFlattenCompositingLayers);
   3129                 m_frame->view()->paintContents(&context, visibleRect);
   3130                 m_frame->view()->setPaintBehavior(oldBehavior);
   3131             }
   3132         }
   3133     }
   3134 
   3135     return matchCount;
   3136 }
   3137 
   3138 void Editor::setMarkedTextMatchesAreHighlighted(bool flag)
   3139 {
   3140     if (flag == m_areMarkedTextMatchesHighlighted)
   3141         return;
   3142 
   3143     m_areMarkedTextMatchesHighlighted = flag;
   3144     m_frame->document()->markers()->repaintMarkers(DocumentMarker::TextMatch);
   3145 }
   3146 
   3147 void Editor::respondToChangedSelection(const VisibleSelection& oldSelection, SelectionController::SetSelectionOptions options)
   3148 {
   3149     m_spellingCorrector->stopPendingCorrection(oldSelection);
   3150 
   3151     bool closeTyping = options & SelectionController::CloseTyping;
   3152     bool isContinuousSpellCheckingEnabled = this->isContinuousSpellCheckingEnabled();
   3153     bool isContinuousGrammarCheckingEnabled = isContinuousSpellCheckingEnabled && isGrammarCheckingEnabled();
   3154     if (isContinuousSpellCheckingEnabled) {
   3155         VisibleSelection newAdjacentWords;
   3156         VisibleSelection newSelectedSentence;
   3157         bool caretBrowsing = m_frame->settings() && m_frame->settings()->caretBrowsingEnabled();
   3158         if (m_frame->selection()->selection().isContentEditable() || caretBrowsing) {
   3159             VisiblePosition newStart(m_frame->selection()->selection().visibleStart());
   3160             newAdjacentWords = VisibleSelection(startOfWord(newStart, LeftWordIfOnBoundary), endOfWord(newStart, RightWordIfOnBoundary));
   3161             if (isContinuousGrammarCheckingEnabled)
   3162                 newSelectedSentence = VisibleSelection(startOfSentence(newStart), endOfSentence(newStart));
   3163         }
   3164 
   3165         // Don't check spelling and grammar if the change of selection is triggered by spelling correction itself.
   3166         bool shouldCheckSpellingAndGrammar = !(options & SelectionController::SpellCorrectionTriggered);
   3167 
   3168         // When typing we check spelling elsewhere, so don't redo it here.
   3169         // If this is a change in selection resulting from a delete operation,
   3170         // oldSelection may no longer be in the document.
   3171         if (shouldCheckSpellingAndGrammar && closeTyping && oldSelection.isContentEditable() && oldSelection.start().deprecatedNode() && oldSelection.start().anchorNode()->inDocument()) {
   3172             VisiblePosition oldStart(oldSelection.visibleStart());
   3173             VisibleSelection oldAdjacentWords = VisibleSelection(startOfWord(oldStart, LeftWordIfOnBoundary), endOfWord(oldStart, RightWordIfOnBoundary));
   3174             if (oldAdjacentWords != newAdjacentWords) {
   3175                 if (isContinuousGrammarCheckingEnabled) {
   3176                     VisibleSelection oldSelectedSentence = VisibleSelection(startOfSentence(oldStart), endOfSentence(oldStart));
   3177                     markMisspellingsAndBadGrammar(oldAdjacentWords, oldSelectedSentence != newSelectedSentence, oldSelectedSentence);
   3178                 } else
   3179                     markMisspellingsAndBadGrammar(oldAdjacentWords, false, oldAdjacentWords);
   3180             }
   3181         }
   3182 
   3183 #if !PLATFORM(MAC) || (PLATFORM(MAC) && (defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD) || defined(BUILDING_ON_SNOW_LEOPARD)))
   3184         // This only erases markers that are in the first unit (word or sentence) of the selection.
   3185         // Perhaps peculiar, but it matches AppKit on these Mac OSX versions.
   3186         if (RefPtr<Range> wordRange = newAdjacentWords.toNormalizedRange())
   3187             m_frame->document()->markers()->removeMarkers(wordRange.get(), DocumentMarker::Spelling);
   3188 #endif
   3189         if (RefPtr<Range> sentenceRange = newSelectedSentence.toNormalizedRange())
   3190             m_frame->document()->markers()->removeMarkers(sentenceRange.get(), DocumentMarker::Grammar);
   3191     }
   3192 
   3193     // When continuous spell checking is off, existing markers disappear after the selection changes.
   3194     if (!isContinuousSpellCheckingEnabled)
   3195         m_frame->document()->markers()->removeMarkers(DocumentMarker::Spelling);
   3196     if (!isContinuousGrammarCheckingEnabled)
   3197         m_frame->document()->markers()->removeMarkers(DocumentMarker::Grammar);
   3198 
   3199     respondToChangedSelection(oldSelection);
   3200 }
   3201 
   3202 static Node* findFirstMarkable(Node* node)
   3203 {
   3204     while (node) {
   3205         if (!node->renderer())
   3206             return 0;
   3207         if (node->renderer()->isText())
   3208             return node;
   3209         if (node->renderer()->isTextControl())
   3210             node = toRenderTextControl(node->renderer())->visiblePositionForIndex(1).deepEquivalent().deprecatedNode();
   3211         else if (node->firstChild())
   3212             node = node->firstChild();
   3213         else
   3214             node = node->nextSibling();
   3215     }
   3216 
   3217     return 0;
   3218 }
   3219 
   3220 bool Editor::selectionStartHasMarkerFor(DocumentMarker::MarkerType markerType, int from, int length) const
   3221 {
   3222     Node* node = findFirstMarkable(m_frame->selection()->start().deprecatedNode());
   3223     if (!node)
   3224         return false;
   3225 
   3226     unsigned int startOffset = static_cast<unsigned int>(from);
   3227     unsigned int endOffset = static_cast<unsigned int>(from + length);
   3228     Vector<DocumentMarker> markers = m_frame->document()->markers()->markersForNode(node);
   3229     for (size_t i = 0; i < markers.size(); ++i) {
   3230         DocumentMarker marker = markers[i];
   3231         if (marker.startOffset <= startOffset && endOffset <= marker.endOffset && marker.type == markerType)
   3232             return true;
   3233     }
   3234 
   3235     return false;
   3236 }
   3237 
   3238 FloatRect Editor::windowRectForRange(const Range* range) const
   3239 {
   3240     FrameView* view = frame()->view();
   3241     if (!view)
   3242         return FloatRect();
   3243     Vector<FloatQuad> textQuads;
   3244     range->textQuads(textQuads);
   3245     FloatRect boundingRect;
   3246     size_t size = textQuads.size();
   3247     for (size_t i = 0; i < size; ++i)
   3248         boundingRect.unite(textQuads[i].boundingBox());
   3249     return view->contentsToWindow(IntRect(boundingRect));
   3250 }
   3251 
   3252 TextCheckingTypeMask Editor::textCheckingTypeMaskFor(TextCheckingOptions textCheckingOptions)
   3253 {
   3254     bool shouldMarkSpelling = textCheckingOptions & MarkSpelling;
   3255     bool shouldMarkGrammar = textCheckingOptions & MarkGrammar;
   3256     bool shouldShowCorrectionPanel = textCheckingOptions & ShowCorrectionPanel;
   3257     bool shouldCheckForCorrection = shouldShowCorrectionPanel || (textCheckingOptions & CheckForCorrection);
   3258 
   3259     TextCheckingTypeMask checkingTypes = 0;
   3260     if (shouldMarkSpelling)
   3261         checkingTypes |= TextCheckingTypeSpelling;
   3262     if (shouldMarkGrammar)
   3263         checkingTypes |= TextCheckingTypeGrammar;
   3264     if (shouldCheckForCorrection)
   3265         checkingTypes |= TextCheckingTypeCorrection;
   3266 
   3267 #if USE(AUTOMATIC_TEXT_REPLACEMENT)
   3268     bool shouldPerformReplacement = textCheckingOptions & PerformReplacement;
   3269     if (shouldPerformReplacement) {
   3270         if (isAutomaticLinkDetectionEnabled())
   3271             checkingTypes |= TextCheckingTypeLink;
   3272         if (isAutomaticQuoteSubstitutionEnabled())
   3273             checkingTypes |= TextCheckingTypeQuote;
   3274         if (isAutomaticDashSubstitutionEnabled())
   3275             checkingTypes |= TextCheckingTypeDash;
   3276         if (isAutomaticTextReplacementEnabled())
   3277             checkingTypes |= TextCheckingTypeReplacement;
   3278         if (shouldMarkSpelling && isAutomaticSpellingCorrectionEnabled())
   3279             checkingTypes |= TextCheckingTypeCorrection;
   3280     }
   3281 #endif
   3282 
   3283     return checkingTypes;
   3284 }
   3285 
   3286 } // namespace WebCore
   3287