1/*
2 * Copyright (C) 2006, 2007, 2008, 2011, 2013, 2014 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 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 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 "AlternativeTextController.h"
32#include "ApplyStyleCommand.h"
33#include "CSSComputedStyleDeclaration.h"
34#include "CSSPropertyNames.h"
35#include "CachedResourceLoader.h"
36#include "ClipboardEvent.h"
37#include "CompositionEvent.h"
38#include "CreateLinkCommand.h"
39#include "DataTransfer.h"
40#include "DeleteSelectionCommand.h"
41#include "DictationAlternative.h"
42#include "DictationCommand.h"
43#include "DocumentFragment.h"
44#include "DocumentMarkerController.h"
45#include "EditorClient.h"
46#include "EventHandler.h"
47#include "EventNames.h"
48#include "ExceptionCodePlaceholder.h"
49#include "FocusController.h"
50#include "Frame.h"
51#include "FrameTree.h"
52#include "FrameView.h"
53#include "GraphicsContext.h"
54#include "HTMLFormControlElement.h"
55#include "HTMLFrameOwnerElement.h"
56#include "HTMLImageElement.h"
57#include "HTMLNames.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 "NodeTraversal.h"
67#include "Page.h"
68#include "Pasteboard.h"
69#include "Range.h"
70#include "RemoveFormatCommand.h"
71#include "RenderBlock.h"
72#include "RenderTextControl.h"
73#include "RenderedPosition.h"
74#include "ReplaceSelectionCommand.h"
75#include "Settings.h"
76#include "ShadowRoot.h"
77#include "SimplifyMarkupCommand.h"
78#include "Sound.h"
79#include "SpellChecker.h"
80#include "SpellingCorrectionCommand.h"
81#include "StyleProperties.h"
82#include "TelephoneNumberDetector.h"
83#include "Text.h"
84#include "TextCheckerClient.h"
85#include "TextCheckingHelper.h"
86#include "TextEvent.h"
87#include "TextIterator.h"
88#include "TypingCommand.h"
89#include "UserTypingGestureIndicator.h"
90#include "VisibleUnits.h"
91#include "htmlediting.h"
92#include "markup.h"
93#include <wtf/unicode/CharacterNames.h>
94
95#if ENABLE(DELETION_UI)
96#include "DeleteButtonController.h"
97#endif
98
99#if PLATFORM(IOS)
100#include "DictationCommandIOS.h"
101#include <wtf/text/StringBuilder.h>
102#include <wtf/text/WTFString.h>
103#endif
104
105namespace WebCore {
106
107#if PLATFORM(IOS)
108class ClearTextCommand : public DeleteSelectionCommand {
109public:
110    ClearTextCommand(Document& document);
111    static void CreateAndApply(const RefPtr<Frame> frame);
112
113private:
114    virtual EditAction editingAction() const;
115};
116
117ClearTextCommand::ClearTextCommand(Document& document)
118    : DeleteSelectionCommand(document, false, true, false, false, true)
119{
120}
121
122EditAction ClearTextCommand::editingAction() const
123{
124    return EditActionDelete;
125}
126
127void ClearTextCommand::CreateAndApply(const RefPtr<Frame> frame)
128{
129    if (frame->selection().isNone())
130        return;
131
132    // Don't leave around stale composition state.
133    frame->editor().clear();
134
135    const VisibleSelection oldSelection = frame->selection().selection();
136    frame->selection().selectAll();
137    RefPtr<ClearTextCommand> clearCommand = adoptRef(new ClearTextCommand(*frame->document()));
138    clearCommand->setStartingSelection(oldSelection);
139    applyCommand(clearCommand.release());
140}
141#endif
142
143using namespace HTMLNames;
144using namespace WTF;
145using namespace Unicode;
146
147#if ENABLE(DELETION_UI)
148
149PassRefPtr<Range> Editor::avoidIntersectionWithDeleteButtonController(const Range* range) const
150{
151    if (!range)
152        return 0;
153
154    Node* startContainer = range->startContainer();
155    int startOffset = range->startOffset();
156    Node* endContainer = range->endContainer();
157    int endOffset = range->endOffset();
158
159    if (!startContainer)
160        return 0;
161
162    ASSERT(endContainer);
163
164    Element* element = m_deleteButtonController->containerElement();
165    if (startContainer == element || startContainer->isDescendantOf(element)) {
166        ASSERT(element->parentNode());
167        startContainer = element->parentNode();
168        startOffset = element->nodeIndex();
169    }
170    if (endContainer == element || endContainer->isDescendantOf(element)) {
171        ASSERT(element->parentNode());
172        endContainer = element->parentNode();
173        endOffset = element->nodeIndex();
174    }
175
176    return Range::create(range->ownerDocument(), startContainer, startOffset, endContainer, endOffset);
177}
178
179VisibleSelection Editor::avoidIntersectionWithDeleteButtonController(const VisibleSelection& selection) const
180{
181    if (selection.isNone())
182        return selection;
183
184    Element* element = m_deleteButtonController->containerElement();
185    if (!element)
186        return selection;
187    VisibleSelection updatedSelection = selection;
188
189    Position updatedBase = selection.base();
190    updatePositionForNodeRemoval(updatedBase, element);
191    if (updatedBase != selection.base())
192        updatedSelection.setBase(updatedBase);
193
194    Position updatedExtent = selection.extent();
195    updatePositionForNodeRemoval(updatedExtent, element);
196    if (updatedExtent != selection.extent())
197        updatedSelection.setExtent(updatedExtent);
198
199    return updatedSelection;
200}
201
202#endif
203
204// When an event handler has moved the selection outside of a text control
205// we should use the target control's selection for this editing operation.
206VisibleSelection Editor::selectionForCommand(Event* event)
207{
208    VisibleSelection selection = m_frame.selection().selection();
209    if (!event)
210        return selection;
211    // If the target is a text control, and the current selection is outside of its shadow tree,
212    // then use the saved selection for that text control.
213    HTMLTextFormControlElement* textFormControlOfSelectionStart = enclosingTextFormControl(selection.start());
214    HTMLTextFormControlElement* textFromControlOfTarget = isHTMLTextFormControlElement(*event->target()->toNode()) ? toHTMLTextFormControlElement(event->target()->toNode()) : nullptr;
215    if (textFromControlOfTarget && (selection.start().isNull() || textFromControlOfTarget != textFormControlOfSelectionStart)) {
216        if (RefPtr<Range> range = textFromControlOfTarget->selection())
217            return VisibleSelection(range.get(), DOWNSTREAM, selection.isDirectional());
218    }
219    return selection;
220}
221
222// Function considers Mac editing behavior a fallback when Page or Settings is not available.
223EditingBehavior Editor::behavior() const
224{
225    return EditingBehavior(m_frame.settings().editingBehaviorType());
226}
227
228EditorClient* Editor::client() const
229{
230    if (Page* page = m_frame.page())
231        return page->editorClient();
232    return 0;
233}
234
235
236TextCheckerClient* Editor::textChecker() const
237{
238    if (EditorClient* owner = client())
239        return owner->textChecker();
240    return 0;
241}
242
243void Editor::handleKeyboardEvent(KeyboardEvent* event)
244{
245    if (EditorClient* c = client())
246        c->handleKeyboardEvent(event);
247}
248
249void Editor::handleInputMethodKeydown(KeyboardEvent* event)
250{
251    if (EditorClient* c = client())
252        c->handleInputMethodKeydown(event);
253}
254
255bool Editor::handleTextEvent(TextEvent* event)
256{
257    // Default event handling for Drag and Drop will be handled by DragController
258    // so we leave the event for it.
259    if (event->isDrop())
260        return false;
261
262    if (event->isPaste()) {
263        if (event->pastingFragment())
264#if PLATFORM(IOS)
265        {
266            if (client()->performsTwoStepPaste(event->pastingFragment()))
267                return true;
268#endif
269            replaceSelectionWithFragment(event->pastingFragment(), false, event->shouldSmartReplace(), event->shouldMatchStyle(), event->mailBlockquoteHandling());
270#if PLATFORM(IOS)
271        }
272#endif
273        else
274            replaceSelectionWithText(event->data(), false, event->shouldSmartReplace());
275        return true;
276    }
277
278    String data = event->data();
279    if (data == "\n") {
280        if (event->isLineBreak())
281            return insertLineBreak();
282        return insertParagraphSeparator();
283    }
284
285    return insertTextWithoutSendingTextEvent(data, false, event);
286}
287
288bool Editor::canEdit() const
289{
290    return m_frame.selection().selection().rootEditableElement();
291}
292
293bool Editor::canEditRichly() const
294{
295    return m_frame.selection().selection().isContentRichlyEditable();
296}
297
298// WinIE uses onbeforecut and onbeforepaste to enables the cut and paste menu items.  They
299// also send onbeforecopy, apparently for symmetry, but it doesn't affect the menu items.
300// We need to use onbeforecopy as a real menu enabler because we allow elements that are not
301// normally selectable to implement copy/paste (like divs, or a document body).
302
303bool Editor::canDHTMLCut()
304{
305    return !m_frame.selection().selection().isInPasswordField() && !dispatchCPPEvent(eventNames().beforecutEvent, DataTransferAccessPolicy::Numb);
306}
307
308bool Editor::canDHTMLCopy()
309{
310    return !m_frame.selection().selection().isInPasswordField() && !dispatchCPPEvent(eventNames().beforecopyEvent, DataTransferAccessPolicy::Numb);
311}
312
313bool Editor::canDHTMLPaste()
314{
315    return !dispatchCPPEvent(eventNames().beforepasteEvent, DataTransferAccessPolicy::Numb);
316}
317
318bool Editor::canCut() const
319{
320    return canCopy() && canDelete();
321}
322
323static HTMLImageElement* imageElementFromImageDocument(Document& document)
324{
325    if (!document.isImageDocument())
326        return 0;
327
328    HTMLElement* body = document.body();
329    if (!body)
330        return 0;
331
332    Node* node = body->firstChild();
333    if (!node)
334        return 0;
335    if (!isHTMLImageElement(node))
336        return 0;
337    return toHTMLImageElement(node);
338}
339
340bool Editor::canCopy() const
341{
342    if (imageElementFromImageDocument(document()))
343        return true;
344    const VisibleSelection& selection = m_frame.selection().selection();
345    return selection.isRange() && !selection.isInPasswordField();
346}
347
348bool Editor::canPaste() const
349{
350    return canEdit();
351}
352
353bool Editor::canDelete() const
354{
355    const VisibleSelection& selection = m_frame.selection().selection();
356    return selection.isRange() && selection.rootEditableElement();
357}
358
359bool Editor::canDeleteRange(Range* range) const
360{
361    Node* startContainer = range->startContainer();
362    Node* endContainer = range->endContainer();
363    if (!startContainer || !endContainer)
364        return false;
365
366    if (!startContainer->hasEditableStyle() || !endContainer->hasEditableStyle())
367        return false;
368
369    if (range->collapsed(IGNORE_EXCEPTION)) {
370        VisiblePosition start(range->startPosition(), DOWNSTREAM);
371        VisiblePosition previous = start.previous();
372        // FIXME: We sometimes allow deletions at the start of editable roots, like when the caret is in an empty list item.
373        if (previous.isNull() || previous.deepEquivalent().deprecatedNode()->rootEditableElement() != startContainer->rootEditableElement())
374            return false;
375    }
376    return true;
377}
378
379bool Editor::smartInsertDeleteEnabled()
380{
381    return client() && client()->smartInsertDeleteEnabled();
382}
383
384bool Editor::canSmartCopyOrDelete()
385{
386    return client() && client()->smartInsertDeleteEnabled() && m_frame.selection().granularity() == WordGranularity;
387}
388
389bool Editor::isSelectTrailingWhitespaceEnabled()
390{
391    return client() && client()->isSelectTrailingWhitespaceEnabled();
392}
393
394bool Editor::deleteWithDirection(SelectionDirection direction, TextGranularity granularity, bool killRing, bool isTypingAction)
395{
396    if (!canEdit())
397        return false;
398
399    if (m_frame.selection().isRange()) {
400        if (isTypingAction) {
401            TypingCommand::deleteKeyPressed(document(), canSmartCopyOrDelete() ? TypingCommand::SmartDelete : 0, granularity);
402            revealSelectionAfterEditingOperation();
403        } else {
404            if (killRing)
405                addToKillRing(selectedRange().get(), false);
406            deleteSelectionWithSmartDelete(canSmartCopyOrDelete());
407            // Implicitly calls revealSelectionAfterEditingOperation().
408        }
409    } else {
410        TypingCommand::Options options = 0;
411        if (canSmartCopyOrDelete())
412            options |= TypingCommand::SmartDelete;
413        if (killRing)
414            options |= TypingCommand::KillRing;
415        switch (direction) {
416        case DirectionForward:
417        case DirectionRight:
418            TypingCommand::forwardDeleteKeyPressed(document(), options, granularity);
419            break;
420        case DirectionBackward:
421        case DirectionLeft:
422            TypingCommand::deleteKeyPressed(document(), options, granularity);
423            break;
424        }
425        revealSelectionAfterEditingOperation();
426    }
427
428    // FIXME: We should to move this down into deleteKeyPressed.
429    // clear the "start new kill ring sequence" setting, because it was set to true
430    // when the selection was updated by deleting the range
431    if (killRing)
432        setStartNewKillRingSequence(false);
433
434    return true;
435}
436
437void Editor::deleteSelectionWithSmartDelete(bool smartDelete)
438{
439    if (m_frame.selection().isNone())
440        return;
441
442    applyCommand(DeleteSelectionCommand::create(document(), smartDelete));
443}
444
445#if PLATFORM(IOS)
446void Editor::clearText()
447{
448    ClearTextCommand::CreateAndApply(&m_frame);
449}
450
451void Editor::insertDictationPhrases(PassOwnPtr<Vector<Vector<String> > > dictationPhrases, RetainPtr<id> metadata)
452{
453    if (m_frame.selection().isNone())
454        return;
455
456    if (dictationPhrases->isEmpty())
457        return;
458
459    applyCommand(DictationCommandIOS::create(document(), dictationPhrases, metadata));
460}
461
462void Editor::setDictationPhrasesAsChildOfElement(PassOwnPtr<Vector<Vector<String> > > dictationPhrases, RetainPtr<id> metadata, Element* element)
463{
464    // Clear the composition.
465    clear();
466
467    // Clear the Undo stack, since the operations that follow are not Undoable, and will corrupt the stack.  Some day
468    // we could make them Undoable, and let callers clear the Undo stack explicitly if they wish.
469    clearUndoRedoOperations();
470
471    m_frame.selection().clear();
472
473    element->removeChildren();
474
475    if (dictationPhrases->isEmpty()) {
476        client()->respondToChangedContents();
477        return;
478    }
479
480    ExceptionCode ec;
481    RefPtr<Range> context = document().createRange();
482    context->selectNodeContents(element, ec);
483
484    StringBuilder dictationPhrasesBuilder;
485    size_t dictationPhraseCount = dictationPhrases->size();
486    for (size_t i = 0; i < dictationPhraseCount; i++) {
487        const String& firstInterpretation = dictationPhrases->at(i)[0];
488        dictationPhrasesBuilder.append(firstInterpretation);
489    }
490    String serializedDictationPhrases = dictationPhrasesBuilder.toString();
491
492    element->appendChild(createFragmentFromText(*context.get(), serializedDictationPhrases), ec);
493
494    // We need a layout in order to add markers below.
495    document().updateLayout();
496
497    if (!element->firstChild()->isTextNode()) {
498        // Shouldn't happen.
499        ASSERT(element->firstChild()->isTextNode());
500        return;
501    }
502
503    Text* textNode = static_cast<Text*>(element->firstChild());
504    int previousDictationPhraseStart = 0;
505    for (size_t i = 0; i < dictationPhraseCount; i++) {
506        const Vector<String>& interpretations = dictationPhrases->at(i);
507        int dictationPhraseLength = interpretations[0].length();
508        int dictationPhraseEnd = previousDictationPhraseStart + dictationPhraseLength;
509        if (interpretations.size() > 1) {
510            RefPtr<Range> dictationPhraseRange = Range::create(document(), textNode, previousDictationPhraseStart, textNode, dictationPhraseEnd);
511            document().markers().addDictationPhraseWithAlternativesMarker(dictationPhraseRange.get(), interpretations);
512        }
513        previousDictationPhraseStart = dictationPhraseEnd;
514    }
515
516    RefPtr<Range> resultRange = Range::create(document(), textNode, 0, textNode, textNode->length());
517    document().markers().addDictationResultMarker(resultRange.get(), metadata);
518
519    client()->respondToChangedContents();
520}
521#endif
522
523void Editor::pasteAsPlainText(const String& pastingText, bool smartReplace)
524{
525    Node* target = findEventTargetFromSelection();
526    if (!target)
527        return;
528    target->dispatchEvent(TextEvent::createForPlainTextPaste(document().domWindow(), pastingText, smartReplace), IGNORE_EXCEPTION);
529}
530
531void Editor::pasteAsFragment(PassRefPtr<DocumentFragment> pastingFragment, bool smartReplace, bool matchStyle, MailBlockquoteHandling respectsMailBlockquote)
532{
533    Node* target = findEventTargetFromSelection();
534    if (!target)
535        return;
536    target->dispatchEvent(TextEvent::createForFragmentPaste(document().domWindow(), pastingFragment, smartReplace, matchStyle, respectsMailBlockquote), IGNORE_EXCEPTION);
537}
538
539void Editor::pasteAsPlainTextBypassingDHTML()
540{
541    pasteAsPlainTextWithPasteboard(*Pasteboard::createForCopyAndPaste());
542}
543
544void Editor::pasteAsPlainTextWithPasteboard(Pasteboard& pasteboard)
545{
546    String text = readPlainTextFromPasteboard(pasteboard);
547    if (client() && client()->shouldInsertText(text, selectedRange().get(), EditorInsertActionPasted))
548        pasteAsPlainText(text, canSmartReplaceWithPasteboard(pasteboard));
549}
550
551String Editor::readPlainTextFromPasteboard(Pasteboard& pasteboard)
552{
553    PasteboardPlainText text;
554    pasteboard.read(text);
555    return plainTextFromPasteboard(text);
556}
557
558#if !PLATFORM(MAC)
559
560String Editor::plainTextFromPasteboard(const PasteboardPlainText& text)
561{
562    return text.text;
563}
564
565#endif
566
567#if !PLATFORM(COCOA) && !PLATFORM(EFL)
568void Editor::pasteWithPasteboard(Pasteboard* pasteboard, bool allowPlainText, MailBlockquoteHandling mailBlockquoteHandling)
569{
570    RefPtr<Range> range = selectedRange();
571    if (!range)
572        return;
573
574    bool chosePlainText;
575    RefPtr<DocumentFragment> fragment = pasteboard->documentFragment(m_frame, *range, allowPlainText, chosePlainText);
576    if (fragment && shouldInsertFragment(fragment, range, EditorInsertActionPasted))
577        pasteAsFragment(fragment, canSmartReplaceWithPasteboard(*pasteboard), chosePlainText, mailBlockquoteHandling);
578}
579#endif
580
581bool Editor::canSmartReplaceWithPasteboard(Pasteboard& pasteboard)
582{
583    return client() && client()->smartInsertDeleteEnabled() && pasteboard.canSmartReplace();
584}
585
586bool Editor::shouldInsertFragment(PassRefPtr<DocumentFragment> fragment, PassRefPtr<Range> replacingDOMRange, EditorInsertAction givenAction)
587{
588    if (!client())
589        return false;
590
591    if (fragment) {
592        Node* child = fragment->firstChild();
593        if (child && fragment->lastChild() == child && child->isCharacterDataNode())
594            return client()->shouldInsertText(toCharacterData(child)->data(), replacingDOMRange.get(), givenAction);
595    }
596
597    return client()->shouldInsertNode(fragment.get(), replacingDOMRange.get(), givenAction);
598}
599
600void Editor::replaceSelectionWithFragment(PassRefPtr<DocumentFragment> fragment, bool selectReplacement, bool smartReplace, bool matchStyle, MailBlockquoteHandling mailBlockquoteHandling)
601{
602    VisibleSelection selection = m_frame.selection().selection();
603    if (selection.isNone() || !selection.isContentEditable() || !fragment)
604        return;
605
606    ReplaceSelectionCommand::CommandOptions options = ReplaceSelectionCommand::PreventNesting | ReplaceSelectionCommand::SanitizeFragment;
607    if (selectReplacement)
608        options |= ReplaceSelectionCommand::SelectReplacement;
609    if (smartReplace)
610        options |= ReplaceSelectionCommand::SmartReplace;
611    if (matchStyle)
612        options |= ReplaceSelectionCommand::MatchStyle;
613    if (mailBlockquoteHandling == MailBlockquoteHandling::IgnoreBlockquote)
614        options |= ReplaceSelectionCommand::IgnoreMailBlockquote;
615
616    applyCommand(ReplaceSelectionCommand::create(document(), fragment, options, EditActionPaste));
617    revealSelectionAfterEditingOperation();
618
619    selection = m_frame.selection().selection();
620    if (selection.isInPasswordField() || !isContinuousSpellCheckingEnabled())
621        return;
622    Node* nodeToCheck = selection.rootEditableElement();
623    if (!nodeToCheck)
624        return;
625
626    RefPtr<Range> rangeToCheck = Range::create(document(), firstPositionInNode(nodeToCheck), lastPositionInNode(nodeToCheck));
627    m_spellChecker->requestCheckingFor(SpellCheckRequest::create(resolveTextCheckingTypeMask(TextCheckingTypeSpelling | TextCheckingTypeGrammar), TextCheckingProcessBatch, rangeToCheck, rangeToCheck));
628}
629
630void Editor::replaceSelectionWithText(const String& text, bool selectReplacement, bool smartReplace)
631{
632    RefPtr<Range> range = selectedRange();
633    if (!range)
634        return;
635
636    replaceSelectionWithFragment(createFragmentFromText(*range, text), selectReplacement, smartReplace, true);
637}
638
639PassRefPtr<Range> Editor::selectedRange()
640{
641    return m_frame.selection().toNormalizedRange();
642}
643
644#if PLATFORM(IOS)
645void Editor::confirmMarkedText()
646{
647    // FIXME: This is a hacky workaround for the keyboard calling this method too late -
648    // after the selection and focus have already changed.  See <rdar://problem/5975559>
649    Element* focused = document().focusedElement();
650    Node* composition = compositionNode();
651
652    if (composition && focused && focused != composition && !composition->isDescendantOrShadowDescendantOf(focused)) {
653        cancelComposition();
654        document().setFocusedElement(focused);
655    } else
656        confirmComposition();
657}
658
659void Editor::setTextAsChildOfElement(const String& text, Element* elem)
660{
661    // Clear the composition
662    clear();
663
664    // Clear the Undo stack, since the operations that follow are not Undoable, and will corrupt the stack.  Some day
665    // we could make them Undoable, and let callers clear the Undo stack explicitly if they wish.
666    clearUndoRedoOperations();
667
668    // If the element is empty already and we're not adding text, we can early return and avoid clearing/setting
669    // a selection at [0, 0] and the expense involved in creation VisiblePositions.
670    if (!elem->firstChild() && text.isEmpty())
671        return;
672
673    // As a side effect this function sets a caret selection after the inserted content.  Much of what
674    // follows is more expensive if there is a selection, so clear it since it's going to change anyway.
675    m_frame.selection().clear();
676
677    // clear out all current children of element
678    elem->removeChildren();
679
680    if (text.length()) {
681        // insert new text
682        // remove element from tree while doing it
683        // FIXME: The element we're inserting into is often the body element.  It seems strange to be removing it
684        // (even if it is only temporary).  ReplaceSelectionCommand doesn't bother doing this when it inserts
685        // content, why should we here?
686        ExceptionCode ec;
687        RefPtr<Node> parent = elem->parentNode();
688        RefPtr<Node> siblingAfter = elem->nextSibling();
689        if (parent)
690            elem->remove(ec);
691
692        RefPtr<Range> context = document().createRange();
693        context->selectNodeContents(elem, ec);
694        RefPtr<DocumentFragment> fragment = createFragmentFromText(*context.get(), text);
695        elem->appendChild(fragment, ec);
696
697        // restore element to document
698        if (parent) {
699            if (siblingAfter)
700                parent->insertBefore(elem, siblingAfter.get(), ec);
701            else
702                parent->appendChild(elem, ec);
703        }
704    }
705
706    // set the selection to the end
707    VisibleSelection selection;
708
709    Position pos = createLegacyEditingPosition(elem, elem->childNodeCount());
710
711    VisiblePosition visiblePos(pos, VP_DEFAULT_AFFINITY);
712    if (visiblePos.isNull())
713        return;
714
715    selection.setBase(visiblePos);
716    selection.setExtent(visiblePos);
717
718    m_frame.selection().setSelection(selection);
719
720    client()->respondToChangedContents();
721}
722#endif
723
724bool Editor::shouldDeleteRange(Range* range) const
725{
726    if (!range || range->collapsed(IGNORE_EXCEPTION))
727        return false;
728
729    if (!canDeleteRange(range))
730        return false;
731
732    return client() && client()->shouldDeleteRange(range);
733}
734
735bool Editor::tryDHTMLCopy()
736{
737    if (m_frame.selection().selection().isInPasswordField())
738        return false;
739
740    return !dispatchCPPEvent(eventNames().copyEvent, DataTransferAccessPolicy::Writable);
741}
742
743bool Editor::tryDHTMLCut()
744{
745    if (m_frame.selection().selection().isInPasswordField())
746        return false;
747
748    return !dispatchCPPEvent(eventNames().cutEvent, DataTransferAccessPolicy::Writable);
749}
750
751bool Editor::tryDHTMLPaste()
752{
753    return !dispatchCPPEvent(eventNames().pasteEvent, DataTransferAccessPolicy::Readable);
754}
755
756bool Editor::shouldInsertText(const String& text, Range* range, EditorInsertAction action) const
757{
758    return client() && client()->shouldInsertText(text, range, action);
759}
760
761void Editor::respondToChangedContents(const VisibleSelection& endingSelection)
762{
763    if (AXObjectCache::accessibilityEnabled()) {
764        Node* node = endingSelection.start().deprecatedNode();
765        if (AXObjectCache* cache = document().existingAXObjectCache())
766            cache->postNotification(node, AXObjectCache::AXValueChanged, TargetObservableParent);
767    }
768
769    updateMarkersForWordsAffectedByEditing(true);
770
771    if (client())
772        client()->respondToChangedContents();
773}
774
775bool Editor::hasBidiSelection() const
776{
777    if (m_frame.selection().isNone())
778        return false;
779
780    Node* startNode;
781    if (m_frame.selection().isRange()) {
782        startNode = m_frame.selection().selection().start().downstream().deprecatedNode();
783        Node* endNode = m_frame.selection().selection().end().upstream().deprecatedNode();
784        if (enclosingBlock(startNode) != enclosingBlock(endNode))
785            return false;
786    } else
787        startNode = m_frame.selection().selection().visibleStart().deepEquivalent().deprecatedNode();
788
789    auto renderer = startNode->renderer();
790    while (renderer && !renderer->isRenderBlockFlow())
791        renderer = renderer->parent();
792
793    if (!renderer)
794        return false;
795
796    if (!renderer->style().isLeftToRightDirection())
797        return true;
798
799    return toRenderBlockFlow(renderer)->containsNonZeroBidiLevel();
800}
801
802TriState Editor::selectionUnorderedListState() const
803{
804    if (m_frame.selection().isCaret()) {
805        if (enclosingElementWithTag(m_frame.selection().selection().start(), ulTag))
806            return TrueTriState;
807    } else if (m_frame.selection().isRange()) {
808        auto* startNode = enclosingElementWithTag(m_frame.selection().selection().start(), ulTag);
809        auto* endNode = enclosingElementWithTag(m_frame.selection().selection().end(), ulTag);
810        if (startNode && endNode && startNode == endNode)
811            return TrueTriState;
812    }
813
814    return FalseTriState;
815}
816
817TriState Editor::selectionOrderedListState() const
818{
819    if (m_frame.selection().isCaret()) {
820        if (enclosingElementWithTag(m_frame.selection().selection().start(), olTag))
821            return TrueTriState;
822    } else if (m_frame.selection().isRange()) {
823        auto* startNode = enclosingElementWithTag(m_frame.selection().selection().start(), olTag);
824        auto* endNode = enclosingElementWithTag(m_frame.selection().selection().end(), olTag);
825        if (startNode && endNode && startNode == endNode)
826            return TrueTriState;
827    }
828
829    return FalseTriState;
830}
831
832PassRefPtr<Node> Editor::insertOrderedList()
833{
834    if (!canEditRichly())
835        return 0;
836
837    RefPtr<Node> newList = InsertListCommand::insertList(document(), InsertListCommand::OrderedList);
838    revealSelectionAfterEditingOperation();
839    return newList;
840}
841
842PassRefPtr<Node> Editor::insertUnorderedList()
843{
844    if (!canEditRichly())
845        return 0;
846
847    RefPtr<Node> newList = InsertListCommand::insertList(document(), InsertListCommand::UnorderedList);
848    revealSelectionAfterEditingOperation();
849    return newList;
850}
851
852bool Editor::canIncreaseSelectionListLevel()
853{
854    return canEditRichly() && IncreaseSelectionListLevelCommand::canIncreaseSelectionListLevel(&document());
855}
856
857bool Editor::canDecreaseSelectionListLevel()
858{
859    return canEditRichly() && DecreaseSelectionListLevelCommand::canDecreaseSelectionListLevel(&document());
860}
861
862PassRefPtr<Node> Editor::increaseSelectionListLevel()
863{
864    if (!canEditRichly() || m_frame.selection().isNone())
865        return 0;
866
867    RefPtr<Node> newList = IncreaseSelectionListLevelCommand::increaseSelectionListLevel(&document());
868    revealSelectionAfterEditingOperation();
869    return newList;
870}
871
872PassRefPtr<Node> Editor::increaseSelectionListLevelOrdered()
873{
874    if (!canEditRichly() || m_frame.selection().isNone())
875        return 0;
876
877    RefPtr<Node> newList = IncreaseSelectionListLevelCommand::increaseSelectionListLevelOrdered(&document());
878    revealSelectionAfterEditingOperation();
879    return newList.release();
880}
881
882PassRefPtr<Node> Editor::increaseSelectionListLevelUnordered()
883{
884    if (!canEditRichly() || m_frame.selection().isNone())
885        return 0;
886
887    RefPtr<Node> newList = IncreaseSelectionListLevelCommand::increaseSelectionListLevelUnordered(&document());
888    revealSelectionAfterEditingOperation();
889    return newList.release();
890}
891
892void Editor::decreaseSelectionListLevel()
893{
894    if (!canEditRichly() || m_frame.selection().isNone())
895        return;
896
897    DecreaseSelectionListLevelCommand::decreaseSelectionListLevel(&document());
898    revealSelectionAfterEditingOperation();
899}
900
901void Editor::removeFormattingAndStyle()
902{
903    applyCommand(RemoveFormatCommand::create(document()));
904}
905
906void Editor::clearLastEditCommand()
907{
908    m_lastEditCommand.clear();
909}
910#if PLATFORM(IOS)
911// If the selection is adjusted from UIKit without closing the typing, the typing command may
912// have a stale selection.
913void Editor::ensureLastEditCommandHasCurrentSelectionIfOpenForMoreTyping()
914{
915    TypingCommand::ensureLastEditCommandHasCurrentSelectionIfOpenForMoreTyping(&m_frame, m_frame.selection().selection());
916}
917#endif
918
919// Returns whether caller should continue with "the default processing", which is the same as
920// the event handler NOT setting the return value to false
921bool Editor::dispatchCPPEvent(const AtomicString& eventType, DataTransferAccessPolicy policy)
922{
923    Node* target = findEventTargetFromSelection();
924    if (!target)
925        return true;
926
927    RefPtr<DataTransfer> dataTransfer = DataTransfer::createForCopyAndPaste(policy);
928
929    RefPtr<Event> event = ClipboardEvent::create(eventType, true, true, dataTransfer);
930    target->dispatchEvent(event, IGNORE_EXCEPTION);
931    bool noDefaultProcessing = event->defaultPrevented();
932    if (noDefaultProcessing && policy == DataTransferAccessPolicy::Writable) {
933        OwnPtr<Pasteboard> pasteboard = Pasteboard::createForCopyAndPaste();
934        pasteboard->clear();
935        pasteboard->writePasteboard(dataTransfer->pasteboard());
936    }
937
938    // invalidate dataTransfer here for security
939    dataTransfer->setAccessPolicy(DataTransferAccessPolicy::Numb);
940
941    return !noDefaultProcessing;
942}
943
944Node* Editor::findEventTargetFrom(const VisibleSelection& selection) const
945{
946    Node* target = selection.start().element();
947    if (!target)
948        target = document().body();
949    if (!target)
950        return 0;
951
952    return target;
953}
954
955Node* Editor::findEventTargetFromSelection() const
956{
957    return findEventTargetFrom(m_frame.selection().selection());
958}
959
960void Editor::applyStyle(StyleProperties* style, EditAction editingAction)
961{
962    switch (m_frame.selection().selection().selectionType()) {
963    case VisibleSelection::NoSelection:
964        // do nothing
965        break;
966    case VisibleSelection::CaretSelection:
967        computeAndSetTypingStyle(style, editingAction);
968        break;
969    case VisibleSelection::RangeSelection:
970        if (style)
971            applyCommand(ApplyStyleCommand::create(document(), EditingStyle::create(style).get(), editingAction));
972        break;
973    }
974}
975
976bool Editor::shouldApplyStyle(StyleProperties* style, Range* range)
977{
978    return client()->shouldApplyStyle(style, range);
979}
980
981void Editor::applyParagraphStyle(StyleProperties* style, EditAction editingAction)
982{
983    switch (m_frame.selection().selection().selectionType()) {
984    case VisibleSelection::NoSelection:
985        // do nothing
986        break;
987    case VisibleSelection::CaretSelection:
988    case VisibleSelection::RangeSelection:
989        if (style)
990            applyCommand(ApplyStyleCommand::create(document(), EditingStyle::create(style).get(), editingAction, ApplyStyleCommand::ForceBlockProperties));
991        break;
992    }
993}
994
995void Editor::applyStyleToSelection(StyleProperties* style, EditAction editingAction)
996{
997    if (!style || style->isEmpty() || !canEditRichly())
998        return;
999
1000    if (client() && client()->shouldApplyStyle(style, m_frame.selection().toNormalizedRange().get()))
1001        applyStyle(style, editingAction);
1002}
1003
1004void Editor::applyParagraphStyleToSelection(StyleProperties* style, EditAction editingAction)
1005{
1006    if (!style || style->isEmpty() || !canEditRichly())
1007        return;
1008
1009    if (client() && client()->shouldApplyStyle(style, m_frame.selection().toNormalizedRange().get()))
1010        applyParagraphStyle(style, editingAction);
1011}
1012
1013bool Editor::selectionStartHasStyle(CSSPropertyID propertyID, const String& value) const
1014{
1015    return EditingStyle::create(propertyID, value)->triStateOfStyle(
1016        EditingStyle::styleAtSelectionStart(m_frame.selection().selection(), propertyID == CSSPropertyBackgroundColor).get());
1017}
1018
1019TriState Editor::selectionHasStyle(CSSPropertyID propertyID, const String& value) const
1020{
1021    return EditingStyle::create(propertyID, value)->triStateOfStyle(m_frame.selection().selection());
1022}
1023
1024String Editor::selectionStartCSSPropertyValue(CSSPropertyID propertyID)
1025{
1026    RefPtr<EditingStyle> selectionStyle = EditingStyle::styleAtSelectionStart(m_frame.selection().selection(),
1027        propertyID == CSSPropertyBackgroundColor);
1028    if (!selectionStyle || !selectionStyle->style())
1029        return String();
1030
1031    if (propertyID == CSSPropertyFontSize)
1032        return String::number(selectionStyle->legacyFontSize(&document()));
1033    return selectionStyle->style()->getPropertyValue(propertyID);
1034}
1035
1036void Editor::indent()
1037{
1038    applyCommand(IndentOutdentCommand::create(document(), IndentOutdentCommand::Indent));
1039}
1040
1041void Editor::outdent()
1042{
1043    applyCommand(IndentOutdentCommand::create(document(), IndentOutdentCommand::Outdent));
1044}
1045
1046static void notifyTextFromControls(Element* startRoot, Element* endRoot)
1047{
1048    HTMLTextFormControlElement* startingTextControl = enclosingTextFormControl(firstPositionInOrBeforeNode(startRoot));
1049    HTMLTextFormControlElement* endingTextControl = enclosingTextFormControl(firstPositionInOrBeforeNode(endRoot));
1050    if (startingTextControl)
1051        startingTextControl->didEditInnerTextValue();
1052    if (endingTextControl && startingTextControl != endingTextControl)
1053        endingTextControl->didEditInnerTextValue();
1054}
1055
1056static void dispatchEditableContentChangedEvents(PassRefPtr<Element> prpStartRoot, PassRefPtr<Element> prpEndRoot)
1057{
1058    RefPtr<Element> startRoot = prpStartRoot;
1059    RefPtr<Element> endRoot = prpEndRoot;
1060    if (startRoot)
1061        startRoot->dispatchEvent(Event::create(eventNames().webkitEditableContentChangedEvent, false, false), IGNORE_EXCEPTION);
1062    if (endRoot && endRoot != startRoot)
1063        endRoot->dispatchEvent(Event::create(eventNames().webkitEditableContentChangedEvent, false, false), IGNORE_EXCEPTION);
1064}
1065
1066void Editor::appliedEditing(PassRefPtr<CompositeEditCommand> cmd)
1067{
1068    document().updateLayout();
1069
1070    EditCommandComposition* composition = cmd->composition();
1071    ASSERT(composition);
1072    VisibleSelection newSelection(cmd->endingSelection());
1073
1074    notifyTextFromControls(composition->startingRootEditableElement(), composition->endingRootEditableElement());
1075
1076    // Don't clear the typing style with this selection change.  We do those things elsewhere if necessary.
1077    FrameSelection::SetSelectionOptions options = cmd->isDictationCommand() ? FrameSelection::DictationTriggered : 0;
1078    changeSelectionAfterCommand(newSelection, options);
1079    dispatchEditableContentChangedEvents(composition->startingRootEditableElement(), composition->endingRootEditableElement());
1080
1081    updateEditorUINowIfScheduled();
1082
1083    m_alternativeTextController->respondToAppliedEditing(cmd.get());
1084
1085    if (!cmd->preservesTypingStyle())
1086        m_frame.selection().clearTypingStyle();
1087
1088    // Command will be equal to last edit command only in the case of typing
1089    if (m_lastEditCommand.get() == cmd)
1090        ASSERT(cmd->isTypingCommand());
1091    else {
1092        // Only register a new undo command if the command passed in is
1093        // different from the last command
1094        m_lastEditCommand = cmd;
1095        if (client())
1096            client()->registerUndoStep(m_lastEditCommand->ensureComposition());
1097    }
1098
1099    respondToChangedContents(newSelection);
1100}
1101
1102void Editor::unappliedEditing(PassRefPtr<EditCommandComposition> cmd)
1103{
1104    document().updateLayout();
1105
1106    notifyTextFromControls(cmd->startingRootEditableElement(), cmd->endingRootEditableElement());
1107
1108    VisibleSelection newSelection(cmd->startingSelection());
1109    changeSelectionAfterCommand(newSelection, FrameSelection::defaultSetSelectionOptions());
1110    dispatchEditableContentChangedEvents(cmd->startingRootEditableElement(), cmd->endingRootEditableElement());
1111
1112    updateEditorUINowIfScheduled();
1113
1114    m_alternativeTextController->respondToUnappliedEditing(cmd.get());
1115
1116    m_lastEditCommand = 0;
1117    if (client())
1118        client()->registerRedoStep(cmd);
1119    respondToChangedContents(newSelection);
1120}
1121
1122void Editor::reappliedEditing(PassRefPtr<EditCommandComposition> cmd)
1123{
1124    document().updateLayout();
1125
1126    notifyTextFromControls(cmd->startingRootEditableElement(), cmd->endingRootEditableElement());
1127
1128    VisibleSelection newSelection(cmd->endingSelection());
1129    changeSelectionAfterCommand(newSelection, FrameSelection::defaultSetSelectionOptions());
1130    dispatchEditableContentChangedEvents(cmd->startingRootEditableElement(), cmd->endingRootEditableElement());
1131
1132    updateEditorUINowIfScheduled();
1133
1134    m_lastEditCommand = 0;
1135    if (client())
1136        client()->registerUndoStep(cmd);
1137    respondToChangedContents(newSelection);
1138}
1139
1140Editor::Editor(Frame& frame)
1141    : m_frame(frame)
1142#if ENABLE(DELETION_UI)
1143    , m_deleteButtonController(std::make_unique<DeleteButtonController>(frame))
1144#endif
1145    , m_ignoreCompositionSelectionChange(false)
1146    , m_shouldStartNewKillRingSequence(false)
1147    // This is off by default, since most editors want this behavior (this matches IE but not FF).
1148    , m_shouldStyleWithCSS(false)
1149    , m_killRing(std::make_unique<KillRing>())
1150    , m_spellChecker(std::make_unique<SpellChecker>(frame))
1151    , m_alternativeTextController(std::make_unique<AlternativeTextController>(frame))
1152    , m_areMarkedTextMatchesHighlighted(false)
1153    , m_defaultParagraphSeparator(EditorParagraphSeparatorIsDiv)
1154    , m_overwriteModeEnabled(false)
1155    , m_editorUIUpdateTimer(this, &Editor::editorUIUpdateTimerFired)
1156    , m_editorUIUpdateTimerShouldCheckSpellingAndGrammar(false)
1157    , m_editorUIUpdateTimerWasTriggeredByDictation(false)
1158#if ENABLE(TELEPHONE_NUMBER_DETECTION) && !PLATFORM(IOS)
1159    , m_telephoneNumberDetectionUpdateTimer(this, &Editor::scanSelectionForTelephoneNumbers)
1160#endif
1161{
1162}
1163
1164Editor::~Editor()
1165{
1166}
1167
1168void Editor::clear()
1169{
1170    m_compositionNode = 0;
1171    m_customCompositionUnderlines.clear();
1172    m_shouldStyleWithCSS = false;
1173    m_defaultParagraphSeparator = EditorParagraphSeparatorIsDiv;
1174
1175#if ENABLE(DELETION_UI)
1176    m_deleteButtonController = std::make_unique<DeleteButtonController>(m_frame);
1177#endif
1178}
1179
1180bool Editor::insertText(const String& text, Event* triggeringEvent)
1181{
1182    return m_frame.eventHandler().handleTextInputEvent(text, triggeringEvent);
1183}
1184
1185bool Editor::insertTextForConfirmedComposition(const String& text)
1186{
1187    return m_frame.eventHandler().handleTextInputEvent(text, 0, TextEventInputComposition);
1188}
1189
1190bool Editor::insertDictatedText(const String& text, const Vector<DictationAlternative>& dictationAlternatives, Event* triggeringEvent)
1191{
1192    return m_alternativeTextController->insertDictatedText(text, dictationAlternatives, triggeringEvent);
1193}
1194
1195bool Editor::insertTextWithoutSendingTextEvent(const String& text, bool selectInsertedText, TextEvent* triggeringEvent)
1196{
1197    if (text.isEmpty())
1198        return false;
1199
1200    VisibleSelection selection = selectionForCommand(triggeringEvent);
1201    if (!selection.isContentEditable())
1202        return false;
1203    RefPtr<Range> range = selection.toNormalizedRange();
1204
1205    if (!shouldInsertText(text, range.get(), EditorInsertActionTyped))
1206        return true;
1207
1208    updateMarkersForWordsAffectedByEditing(isSpaceOrNewline(text[0]));
1209
1210    bool shouldConsiderApplyingAutocorrection = false;
1211    if (text == " " || text == "\t")
1212        shouldConsiderApplyingAutocorrection = true;
1213
1214    if (text.length() == 1 && u_ispunct(text[0]) && !isAmbiguousBoundaryCharacter(text[0]))
1215        shouldConsiderApplyingAutocorrection = true;
1216
1217    bool autocorrectionWasApplied = shouldConsiderApplyingAutocorrection && m_alternativeTextController->applyAutocorrectionBeforeTypingIfAppropriate();
1218
1219    // Get the selection to use for the event that triggered this insertText.
1220    // If the event handler changed the selection, we may want to use a different selection
1221    // that is contained in the event target.
1222    selection = selectionForCommand(triggeringEvent);
1223    if (selection.isContentEditable()) {
1224        if (Node* selectionStart = selection.start().deprecatedNode()) {
1225            Ref<Document> document(selectionStart->document());
1226
1227            // Insert the text
1228            if (triggeringEvent && triggeringEvent->isDictation())
1229                DictationCommand::insertText(&document.get(), text, triggeringEvent->dictationAlternatives(), selection);
1230            else {
1231                TypingCommand::Options options = 0;
1232                if (selectInsertedText)
1233                    options |= TypingCommand::SelectInsertedText;
1234                if (autocorrectionWasApplied)
1235                    options |= TypingCommand::RetainAutocorrectionIndicator;
1236                TypingCommand::insertText(document.get(), text, selection, options, triggeringEvent && triggeringEvent->isComposition() ? TypingCommand::TextCompositionConfirm : TypingCommand::TextCompositionNone);
1237            }
1238
1239            // Reveal the current selection
1240            if (Frame* editedFrame = document->frame())
1241                if (Page* page = editedFrame->page())
1242                    page->focusController().focusedOrMainFrame().selection().revealSelection(ScrollAlignment::alignCenterIfNeeded);
1243        }
1244    }
1245
1246    return true;
1247}
1248
1249bool Editor::insertLineBreak()
1250{
1251    if (!canEdit())
1252        return false;
1253
1254    if (!shouldInsertText("\n", m_frame.selection().toNormalizedRange().get(), EditorInsertActionTyped))
1255        return true;
1256
1257    VisiblePosition caret = m_frame.selection().selection().visibleStart();
1258    bool alignToEdge = isEndOfEditableOrNonEditableContent(caret);
1259    bool autocorrectionIsApplied = m_alternativeTextController->applyAutocorrectionBeforeTypingIfAppropriate();
1260    TypingCommand::insertLineBreak(document(), autocorrectionIsApplied ? TypingCommand::RetainAutocorrectionIndicator : 0);
1261    revealSelectionAfterEditingOperation(alignToEdge ? ScrollAlignment::alignToEdgeIfNeeded : ScrollAlignment::alignCenterIfNeeded);
1262
1263    return true;
1264}
1265
1266bool Editor::insertParagraphSeparator()
1267{
1268    if (!canEdit())
1269        return false;
1270
1271    if (!canEditRichly())
1272        return insertLineBreak();
1273
1274    if (!shouldInsertText("\n", m_frame.selection().toNormalizedRange().get(), EditorInsertActionTyped))
1275        return true;
1276
1277    VisiblePosition caret = m_frame.selection().selection().visibleStart();
1278    bool alignToEdge = isEndOfEditableOrNonEditableContent(caret);
1279    bool autocorrectionIsApplied = m_alternativeTextController->applyAutocorrectionBeforeTypingIfAppropriate();
1280    TypingCommand::insertParagraphSeparator(document(), autocorrectionIsApplied ? TypingCommand::RetainAutocorrectionIndicator : 0);
1281    revealSelectionAfterEditingOperation(alignToEdge ? ScrollAlignment::alignToEdgeIfNeeded : ScrollAlignment::alignCenterIfNeeded);
1282
1283    return true;
1284}
1285
1286void Editor::cut()
1287{
1288    if (tryDHTMLCut())
1289        return; // DHTML did the whole operation
1290    if (!canCut()) {
1291        systemBeep();
1292        return;
1293    }
1294
1295    performCutOrCopy(CutAction);
1296}
1297
1298void Editor::copy()
1299{
1300    if (tryDHTMLCopy())
1301        return; // DHTML did the whole operation
1302    if (!canCopy()) {
1303        systemBeep();
1304        return;
1305    }
1306
1307    performCutOrCopy(CopyAction);
1308}
1309
1310void Editor::performCutOrCopy(EditorActionSpecifier action)
1311{
1312    RefPtr<Range> selection = selectedRange();
1313    willWriteSelectionToPasteboard(selection);
1314    if (action == CutAction) {
1315        if (!shouldDeleteRange(selection.get()))
1316            return;
1317
1318        updateMarkersForWordsAffectedByEditing(true);
1319    }
1320
1321    if (enclosingTextFormControl(m_frame.selection().selection().start()))
1322        Pasteboard::createForCopyAndPaste()->writePlainText(selectedTextForDataTransfer(), canSmartCopyOrDelete() ? Pasteboard::CanSmartReplace : Pasteboard::CannotSmartReplace);
1323    else {
1324        HTMLImageElement* imageElement = nullptr;
1325        if (action == CopyAction)
1326            imageElement = imageElementFromImageDocument(document());
1327
1328        if (imageElement) {
1329#if PLATFORM(COCOA) || PLATFORM(EFL)
1330            writeImageToPasteboard(*Pasteboard::createForCopyAndPaste(), *imageElement, document().url(), document().title());
1331#else
1332            Pasteboard::createForCopyAndPaste()->writeImage(*imageElement, document().url(), document().title());
1333#endif
1334        } else {
1335#if PLATFORM(COCOA) || PLATFORM(EFL)
1336            writeSelectionToPasteboard(*Pasteboard::createForCopyAndPaste());
1337#else
1338            // FIXME: Convert all other platforms to match Mac and delete this.
1339            Pasteboard::createForCopyAndPaste()->writeSelection(*selection, canSmartCopyOrDelete(), m_frame, IncludeImageAltTextForDataTransfer);
1340#endif
1341        }
1342    }
1343
1344    didWriteSelectionToPasteboard();
1345    if (action == CutAction)
1346        deleteSelectionWithSmartDelete(canSmartCopyOrDelete());
1347}
1348
1349void Editor::paste()
1350{
1351    paste(*Pasteboard::createForCopyAndPaste());
1352}
1353
1354void Editor::paste(Pasteboard& pasteboard)
1355{
1356    if (tryDHTMLPaste())
1357        return; // DHTML did the whole operation
1358    if (!canPaste())
1359        return;
1360    updateMarkersForWordsAffectedByEditing(false);
1361    CachedResourceLoader* loader = document().cachedResourceLoader();
1362    ResourceCacheValidationSuppressor validationSuppressor(loader);
1363    if (m_frame.selection().selection().isContentRichlyEditable())
1364        pasteWithPasteboard(&pasteboard, true);
1365    else
1366        pasteAsPlainTextWithPasteboard(pasteboard);
1367}
1368
1369void Editor::pasteAsPlainText()
1370{
1371    if (tryDHTMLPaste())
1372        return;
1373    if (!canPaste())
1374        return;
1375    updateMarkersForWordsAffectedByEditing(false);
1376    pasteAsPlainTextWithPasteboard(*Pasteboard::createForCopyAndPaste());
1377}
1378
1379void Editor::performDelete()
1380{
1381    if (!canDelete()) {
1382        systemBeep();
1383        return;
1384    }
1385
1386    addToKillRing(selectedRange().get(), false);
1387    deleteSelectionWithSmartDelete(canSmartCopyOrDelete());
1388
1389    // clear the "start new kill ring sequence" setting, because it was set to true
1390    // when the selection was updated by deleting the range
1391    setStartNewKillRingSequence(false);
1392}
1393
1394void Editor::simplifyMarkup(Node* startNode, Node* endNode)
1395{
1396    if (!startNode)
1397        return;
1398    if (endNode) {
1399        if (&startNode->document() != &endNode->document())
1400            return;
1401        // check if start node is before endNode
1402        Node* node = startNode;
1403        while (node && node != endNode)
1404            node = NodeTraversal::next(node);
1405        if (!node)
1406            return;
1407    }
1408
1409    applyCommand(SimplifyMarkupCommand::create(document(), startNode, (endNode) ? NodeTraversal::next(endNode) : 0));
1410}
1411
1412void Editor::copyURL(const URL& url, const String& title)
1413{
1414    copyURL(url, title, *Pasteboard::createForCopyAndPaste());
1415}
1416
1417void Editor::copyURL(const URL& url, const String& title, Pasteboard& pasteboard)
1418{
1419    PasteboardURL pasteboardURL;
1420    pasteboardURL.url = url;
1421    pasteboardURL.title = title;
1422
1423#if PLATFORM(MAC)
1424    fillInUserVisibleForm(pasteboardURL);
1425#endif
1426
1427    pasteboard.write(pasteboardURL);
1428}
1429
1430#if !PLATFORM(IOS)
1431void Editor::copyImage(const HitTestResult& result)
1432{
1433    Element* element = result.innerNonSharedElement();
1434    if (!element)
1435        return;
1436
1437    URL url = result.absoluteLinkURL();
1438    if (url.isEmpty())
1439        url = result.absoluteImageURL();
1440
1441#if PLATFORM(COCOA) || PLATFORM(EFL)
1442    writeImageToPasteboard(*Pasteboard::createForCopyAndPaste(), *element, url, result.altDisplayString());
1443#else
1444    Pasteboard::createForCopyAndPaste()->writeImage(*element, url, result.altDisplayString());
1445#endif
1446}
1447#endif
1448
1449bool Editor::isContinuousSpellCheckingEnabled() const
1450{
1451    return client() && client()->isContinuousSpellCheckingEnabled();
1452}
1453
1454void Editor::toggleContinuousSpellChecking()
1455{
1456    if (client())
1457        client()->toggleContinuousSpellChecking();
1458}
1459
1460bool Editor::isGrammarCheckingEnabled()
1461{
1462    return client() && client()->isGrammarCheckingEnabled();
1463}
1464
1465void Editor::toggleGrammarChecking()
1466{
1467    if (client())
1468        client()->toggleGrammarChecking();
1469}
1470
1471int Editor::spellCheckerDocumentTag()
1472{
1473    return client() ? client()->spellCheckerDocumentTag() : 0;
1474}
1475
1476#if USE(APPKIT)
1477
1478void Editor::uppercaseWord()
1479{
1480    if (client())
1481        client()->uppercaseWord();
1482}
1483
1484void Editor::lowercaseWord()
1485{
1486    if (client())
1487        client()->lowercaseWord();
1488}
1489
1490void Editor::capitalizeWord()
1491{
1492    if (client())
1493        client()->capitalizeWord();
1494}
1495
1496#endif
1497
1498#if USE(AUTOMATIC_TEXT_REPLACEMENT)
1499
1500void Editor::showSubstitutionsPanel()
1501{
1502    if (!client()) {
1503        LOG_ERROR("No NSSpellChecker");
1504        return;
1505    }
1506
1507    if (client()->substitutionsPanelIsShowing()) {
1508        client()->showSubstitutionsPanel(false);
1509        return;
1510    }
1511    client()->showSubstitutionsPanel(true);
1512}
1513
1514bool Editor::substitutionsPanelIsShowing()
1515{
1516    if (!client())
1517        return false;
1518    return client()->substitutionsPanelIsShowing();
1519}
1520
1521void Editor::toggleSmartInsertDelete()
1522{
1523    if (client())
1524        client()->toggleSmartInsertDelete();
1525}
1526
1527bool Editor::isAutomaticQuoteSubstitutionEnabled()
1528{
1529    return client() && client()->isAutomaticQuoteSubstitutionEnabled();
1530}
1531
1532void Editor::toggleAutomaticQuoteSubstitution()
1533{
1534    if (client())
1535        client()->toggleAutomaticQuoteSubstitution();
1536}
1537
1538bool Editor::isAutomaticLinkDetectionEnabled()
1539{
1540    return client() && client()->isAutomaticLinkDetectionEnabled();
1541}
1542
1543void Editor::toggleAutomaticLinkDetection()
1544{
1545    if (client())
1546        client()->toggleAutomaticLinkDetection();
1547}
1548
1549bool Editor::isAutomaticDashSubstitutionEnabled()
1550{
1551    return client() && client()->isAutomaticDashSubstitutionEnabled();
1552}
1553
1554void Editor::toggleAutomaticDashSubstitution()
1555{
1556    if (client())
1557        client()->toggleAutomaticDashSubstitution();
1558}
1559
1560bool Editor::isAutomaticTextReplacementEnabled()
1561{
1562    return client() && client()->isAutomaticTextReplacementEnabled();
1563}
1564
1565void Editor::toggleAutomaticTextReplacement()
1566{
1567    if (client())
1568        client()->toggleAutomaticTextReplacement();
1569}
1570
1571bool Editor::isAutomaticSpellingCorrectionEnabled()
1572{
1573    return m_alternativeTextController->isAutomaticSpellingCorrectionEnabled();
1574}
1575
1576void Editor::toggleAutomaticSpellingCorrection()
1577{
1578    if (client())
1579        client()->toggleAutomaticSpellingCorrection();
1580}
1581
1582#endif
1583
1584bool Editor::shouldEndEditing(Range* range)
1585{
1586    return client() && client()->shouldEndEditing(range);
1587}
1588
1589bool Editor::shouldBeginEditing(Range* range)
1590{
1591    return client() && client()->shouldBeginEditing(range);
1592}
1593
1594void Editor::clearUndoRedoOperations()
1595{
1596    if (client())
1597        client()->clearUndoRedoOperations();
1598}
1599
1600bool Editor::canUndo()
1601{
1602    return client() && client()->canUndo();
1603}
1604
1605void Editor::undo()
1606{
1607    if (client())
1608        client()->undo();
1609}
1610
1611bool Editor::canRedo()
1612{
1613    return client() && client()->canRedo();
1614}
1615
1616void Editor::redo()
1617{
1618    if (client())
1619        client()->redo();
1620}
1621
1622void Editor::didBeginEditing()
1623{
1624    if (client())
1625        client()->didBeginEditing();
1626}
1627
1628void Editor::didEndEditing()
1629{
1630    if (client())
1631        client()->didEndEditing();
1632}
1633
1634void Editor::willWriteSelectionToPasteboard(PassRefPtr<Range> range)
1635{
1636    if (client())
1637        client()->willWriteSelectionToPasteboard(range.get());
1638}
1639
1640void Editor::didWriteSelectionToPasteboard()
1641{
1642    if (client())
1643        client()->didWriteSelectionToPasteboard();
1644}
1645
1646void Editor::toggleBold()
1647{
1648    command("ToggleBold").execute();
1649}
1650
1651void Editor::toggleUnderline()
1652{
1653    command("ToggleUnderline").execute();
1654}
1655
1656void Editor::setBaseWritingDirection(WritingDirection direction)
1657{
1658#if PLATFORM(IOS)
1659    if (inSameParagraph(m_frame.selection().selection().visibleStart(), m_frame.selection().selection().visibleEnd()) &&
1660        baseWritingDirectionForSelectionStart() == direction)
1661        return;
1662#endif
1663
1664    Element* focusedElement = document().focusedElement();
1665    if (focusedElement && isHTMLTextFormControlElement(*focusedElement)) {
1666        if (direction == NaturalWritingDirection)
1667            return;
1668        toHTMLElement(focusedElement)->setAttribute(dirAttr, direction == LeftToRightWritingDirection ? "ltr" : "rtl");
1669        focusedElement->dispatchInputEvent();
1670        document().updateStyleIfNeeded();
1671        return;
1672    }
1673
1674    RefPtr<MutableStyleProperties> style = MutableStyleProperties::create();
1675    style->setProperty(CSSPropertyDirection, direction == LeftToRightWritingDirection ? "ltr" : direction == RightToLeftWritingDirection ? "rtl" : "inherit", false);
1676    applyParagraphStyleToSelection(style.get(), EditActionSetWritingDirection);
1677}
1678
1679WritingDirection Editor::baseWritingDirectionForSelectionStart() const
1680{
1681    WritingDirection result = LeftToRightWritingDirection;
1682
1683    Position pos = m_frame.selection().selection().visibleStart().deepEquivalent();
1684    Node* node = pos.deprecatedNode();
1685    if (!node)
1686        return result;
1687
1688    auto renderer = node->renderer();
1689    if (!renderer)
1690        return result;
1691
1692    if (!renderer->isRenderBlockFlow()) {
1693        renderer = renderer->containingBlock();
1694        if (!renderer)
1695            return result;
1696    }
1697
1698    switch (renderer->style().direction()) {
1699    case LTR:
1700        return LeftToRightWritingDirection;
1701    case RTL:
1702        return RightToLeftWritingDirection;
1703    }
1704
1705    return result;
1706}
1707
1708void Editor::selectComposition()
1709{
1710    RefPtr<Range> range = compositionRange();
1711    if (!range)
1712        return;
1713
1714    // The composition can start inside a composed character sequence, so we have to override checks.
1715    // See <http://bugs.webkit.org/show_bug.cgi?id=15781>
1716    VisibleSelection selection;
1717    selection.setWithoutValidation(range->startPosition(), range->endPosition());
1718    m_frame.selection().setSelection(selection, 0);
1719}
1720
1721void Editor::confirmComposition()
1722{
1723    if (!m_compositionNode)
1724        return;
1725    setComposition(m_compositionNode->data().substring(m_compositionStart, m_compositionEnd - m_compositionStart), ConfirmComposition);
1726}
1727
1728void Editor::cancelComposition()
1729{
1730    if (!m_compositionNode)
1731        return;
1732    setComposition(emptyString(), CancelComposition);
1733}
1734
1735bool Editor::cancelCompositionIfSelectionIsInvalid()
1736{
1737    unsigned start;
1738    unsigned end;
1739    if (!hasComposition() || ignoreCompositionSelectionChange() || getCompositionSelection(start, end))
1740        return false;
1741
1742    cancelComposition();
1743    return true;
1744}
1745
1746void Editor::confirmComposition(const String& text)
1747{
1748    setComposition(text, ConfirmComposition);
1749}
1750
1751void Editor::setComposition(const String& text, SetCompositionMode mode)
1752{
1753    ASSERT(mode == ConfirmComposition || mode == CancelComposition);
1754    UserTypingGestureIndicator typingGestureIndicator(m_frame);
1755
1756    setIgnoreCompositionSelectionChange(true);
1757
1758    if (mode == CancelComposition)
1759        ASSERT(text == emptyString());
1760    else
1761        selectComposition();
1762
1763    if (m_frame.selection().isNone()) {
1764        setIgnoreCompositionSelectionChange(false);
1765        return;
1766    }
1767
1768    // Dispatch a compositionend event to the focused node.
1769    // We should send this event before sending a TextEvent as written in Section 6.2.2 and 6.2.3 of
1770    // the DOM Event specification.
1771    if (Element* target = document().focusedElement()) {
1772        RefPtr<CompositionEvent> event = CompositionEvent::create(eventNames().compositionendEvent, document().domWindow(), text);
1773        target->dispatchEvent(event.release(), IGNORE_EXCEPTION);
1774    }
1775
1776    // If text is empty, then delete the old composition here.  If text is non-empty, InsertTextCommand::input
1777    // will delete the old composition with an optimized replace operation.
1778    if (text.isEmpty() && mode != CancelComposition)
1779        TypingCommand::deleteSelection(document(), 0);
1780
1781    m_compositionNode = 0;
1782    m_customCompositionUnderlines.clear();
1783
1784    insertTextForConfirmedComposition(text);
1785
1786    if (mode == CancelComposition) {
1787        // An open typing command that disagrees about current selection would cause issues with typing later on.
1788        TypingCommand::closeTyping(&m_frame);
1789    }
1790
1791    setIgnoreCompositionSelectionChange(false);
1792}
1793
1794void Editor::setComposition(const String& text, const Vector<CompositionUnderline>& underlines, unsigned selectionStart, unsigned selectionEnd)
1795{
1796    UserTypingGestureIndicator typingGestureIndicator(m_frame);
1797
1798    setIgnoreCompositionSelectionChange(true);
1799
1800    // Updates styles before setting selection for composition to prevent
1801    // inserting the previous composition text into text nodes oddly.
1802    // See https://bugs.webkit.org/show_bug.cgi?id=46868
1803    document().updateStyleIfNeeded();
1804
1805    selectComposition();
1806
1807    if (m_frame.selection().isNone()) {
1808        setIgnoreCompositionSelectionChange(false);
1809        return;
1810    }
1811
1812#if PLATFORM(IOS)
1813    client()->startDelayingAndCoalescingContentChangeNotifications();
1814#endif
1815
1816    Element* target = document().focusedElement();
1817    if (target) {
1818        // Dispatch an appropriate composition event to the focused node.
1819        // We check the composition status and choose an appropriate composition event since this
1820        // function is used for three purposes:
1821        // 1. Starting a new composition.
1822        //    Send a compositionstart and a compositionupdate event when this function creates
1823        //    a new composition node, i.e.
1824        //    m_compositionNode == 0 && !text.isEmpty().
1825        //    Sending a compositionupdate event at this time ensures that at least one
1826        //    compositionupdate event is dispatched.
1827        // 2. Updating the existing composition node.
1828        //    Send a compositionupdate event when this function updates the existing composition
1829        //    node, i.e. m_compositionNode != 0 && !text.isEmpty().
1830        // 3. Canceling the ongoing composition.
1831        //    Send a compositionend event when function deletes the existing composition node, i.e.
1832        //    m_compositionNode != 0 && test.isEmpty().
1833        RefPtr<CompositionEvent> event;
1834        if (!m_compositionNode) {
1835            // We should send a compositionstart event only when the given text is not empty because this
1836            // function doesn't create a composition node when the text is empty.
1837            if (!text.isEmpty()) {
1838                target->dispatchEvent(CompositionEvent::create(eventNames().compositionstartEvent, document().domWindow(), selectedText()));
1839                event = CompositionEvent::create(eventNames().compositionupdateEvent, document().domWindow(), text);
1840            }
1841        } else {
1842            if (!text.isEmpty())
1843                event = CompositionEvent::create(eventNames().compositionupdateEvent, document().domWindow(), text);
1844            else
1845                event = CompositionEvent::create(eventNames().compositionendEvent, document().domWindow(), text);
1846        }
1847        if (event.get())
1848            target->dispatchEvent(event, IGNORE_EXCEPTION);
1849    }
1850
1851    // If text is empty, then delete the old composition here.  If text is non-empty, InsertTextCommand::input
1852    // will delete the old composition with an optimized replace operation.
1853    if (text.isEmpty())
1854        TypingCommand::deleteSelection(document(), TypingCommand::PreventSpellChecking);
1855
1856    m_compositionNode = 0;
1857    m_customCompositionUnderlines.clear();
1858
1859    if (!text.isEmpty()) {
1860        TypingCommand::insertText(document(), text, TypingCommand::SelectInsertedText | TypingCommand::PreventSpellChecking, TypingCommand::TextCompositionUpdate);
1861
1862        // Find out what node has the composition now.
1863        Position base = m_frame.selection().selection().base().downstream();
1864        Position extent = m_frame.selection().selection().extent();
1865        Node* baseNode = base.deprecatedNode();
1866        unsigned baseOffset = base.deprecatedEditingOffset();
1867        Node* extentNode = extent.deprecatedNode();
1868        unsigned extentOffset = extent.deprecatedEditingOffset();
1869
1870        if (baseNode && baseNode == extentNode && baseNode->isTextNode() && baseOffset + text.length() == extentOffset) {
1871            m_compositionNode = toText(baseNode);
1872            m_compositionStart = baseOffset;
1873            m_compositionEnd = extentOffset;
1874            m_customCompositionUnderlines = underlines;
1875            size_t numUnderlines = m_customCompositionUnderlines.size();
1876            for (size_t i = 0; i < numUnderlines; ++i) {
1877                m_customCompositionUnderlines[i].startOffset += baseOffset;
1878                m_customCompositionUnderlines[i].endOffset += baseOffset;
1879            }
1880            if (baseNode->renderer())
1881                baseNode->renderer()->repaint();
1882
1883            unsigned start = std::min(baseOffset + selectionStart, extentOffset);
1884            unsigned end = std::min(std::max(start, baseOffset + selectionEnd), extentOffset);
1885            RefPtr<Range> selectedRange = Range::create(baseNode->document(), baseNode, start, baseNode, end);
1886            m_frame.selection().setSelectedRange(selectedRange.get(), DOWNSTREAM, false);
1887        }
1888    }
1889
1890    setIgnoreCompositionSelectionChange(false);
1891
1892#if PLATFORM(IOS)
1893    client()->stopDelayingAndCoalescingContentChangeNotifications();
1894#endif
1895}
1896
1897void Editor::ignoreSpelling()
1898{
1899    if (!client())
1900        return;
1901
1902    RefPtr<Range> selectedRange = m_frame.selection().toNormalizedRange();
1903    if (selectedRange)
1904        document().markers().removeMarkers(selectedRange.get(), DocumentMarker::Spelling);
1905
1906    String text = selectedText();
1907    ASSERT(text.length());
1908    textChecker()->ignoreWordInSpellDocument(text);
1909}
1910
1911void Editor::learnSpelling()
1912{
1913    if (!client())
1914        return;
1915
1916    // 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>.
1917
1918    RefPtr<Range> selectedRange = m_frame.selection().toNormalizedRange();
1919    if (selectedRange)
1920        document().markers().removeMarkers(selectedRange.get(), DocumentMarker::Spelling);
1921
1922    String text = selectedText();
1923    ASSERT(text.length());
1924    textChecker()->learnWord(text);
1925}
1926
1927#if !PLATFORM(IOS)
1928void Editor::advanceToNextMisspelling(bool startBeforeSelection)
1929{
1930    // The basic approach is to search in two phases - from the selection end to the end of the doc, and
1931    // then we wrap and search from the doc start to (approximately) where we started.
1932
1933    // Start at the end of the selection, search to edge of document.  Starting at the selection end makes
1934    // repeated "check spelling" commands work.
1935    VisibleSelection selection(m_frame.selection().selection());
1936    RefPtr<Range> spellingSearchRange(rangeOfContents(document()));
1937
1938    bool startedWithSelection = false;
1939    if (selection.start().deprecatedNode()) {
1940        startedWithSelection = true;
1941        if (startBeforeSelection) {
1942            VisiblePosition start(selection.visibleStart());
1943            // We match AppKit's rule: Start 1 character before the selection.
1944            VisiblePosition oneBeforeStart = start.previous();
1945            setStart(spellingSearchRange.get(), oneBeforeStart.isNotNull() ? oneBeforeStart : start);
1946        } else
1947            setStart(spellingSearchRange.get(), selection.visibleEnd());
1948    }
1949
1950    Position position = spellingSearchRange->startPosition();
1951    if (!isEditablePosition(position)) {
1952        // This shouldn't happen in very often because the Spelling menu items aren't enabled unless the
1953        // selection is editable.
1954        // This can happen in Mail for a mix of non-editable and editable content (like Stationary),
1955        // when spell checking the whole document before sending the message.
1956        // In that case the document might not be editable, but there are editable pockets that need to be spell checked.
1957
1958        position = firstEditablePositionAfterPositionInRoot(position, document().documentElement()).deepEquivalent();
1959        if (position.isNull())
1960            return;
1961
1962        Position rangeCompliantPosition = position.parentAnchoredEquivalent();
1963        spellingSearchRange->setStart(rangeCompliantPosition.deprecatedNode(), rangeCompliantPosition.deprecatedEditingOffset(), IGNORE_EXCEPTION);
1964        startedWithSelection = false; // won't need to wrap
1965    }
1966
1967    // topNode defines the whole range we want to operate on
1968    Node* topNode = highestEditableRoot(position);
1969    // FIXME: lastOffsetForEditing() is wrong here if editingIgnoresContent(highestEditableRoot()) returns true (e.g. a <table>)
1970    spellingSearchRange->setEnd(topNode, lastOffsetForEditing(topNode), IGNORE_EXCEPTION);
1971
1972    // If spellingSearchRange starts in the middle of a word, advance to the next word so we start checking
1973    // at a word boundary. Going back by one char and then forward by a word does the trick.
1974    if (startedWithSelection) {
1975        VisiblePosition oneBeforeStart = startVisiblePosition(spellingSearchRange.get(), DOWNSTREAM).previous();
1976        if (oneBeforeStart.isNotNull())
1977            setStart(spellingSearchRange.get(), endOfWord(oneBeforeStart));
1978        // else we were already at the start of the editable node
1979    }
1980
1981    if (spellingSearchRange->collapsed(IGNORE_EXCEPTION))
1982        return; // nothing to search in
1983
1984    // Get the spell checker if it is available
1985    if (!client())
1986        return;
1987
1988    // We go to the end of our first range instead of the start of it, just to be sure
1989    // we don't get foiled by any word boundary problems at the start.  It means we might
1990    // do a tiny bit more searching.
1991    Node* searchEndNodeAfterWrap = spellingSearchRange->endContainer();
1992    int searchEndOffsetAfterWrap = spellingSearchRange->endOffset();
1993
1994    int misspellingOffset = 0;
1995    GrammarDetail grammarDetail;
1996    int grammarPhraseOffset = 0;
1997    RefPtr<Range> grammarSearchRange;
1998    String badGrammarPhrase;
1999    String misspelledWord;
2000
2001    bool isSpelling = true;
2002    int foundOffset = 0;
2003    String foundItem;
2004    RefPtr<Range> firstMisspellingRange;
2005    if (unifiedTextCheckerEnabled()) {
2006        grammarSearchRange = spellingSearchRange->cloneRange(IGNORE_EXCEPTION);
2007        foundItem = TextCheckingHelper(client(), spellingSearchRange).findFirstMisspellingOrBadGrammar(isGrammarCheckingEnabled(), isSpelling, foundOffset, grammarDetail);
2008        if (isSpelling) {
2009            misspelledWord = foundItem;
2010            misspellingOffset = foundOffset;
2011        } else {
2012            badGrammarPhrase = foundItem;
2013            grammarPhraseOffset = foundOffset;
2014        }
2015    } else {
2016        misspelledWord = TextCheckingHelper(client(), spellingSearchRange).findFirstMisspelling(misspellingOffset, false, firstMisspellingRange);
2017
2018#if USE(GRAMMAR_CHECKING)
2019        grammarSearchRange = spellingSearchRange->cloneRange(IGNORE_EXCEPTION);
2020        if (!misspelledWord.isEmpty()) {
2021            // Stop looking at start of next misspelled word
2022            CharacterIterator chars(*grammarSearchRange);
2023            chars.advance(misspellingOffset);
2024            grammarSearchRange->setEnd(chars.range()->startContainer(), chars.range()->startOffset(), IGNORE_EXCEPTION);
2025        }
2026
2027        if (isGrammarCheckingEnabled())
2028            badGrammarPhrase = TextCheckingHelper(client(), grammarSearchRange).findFirstBadGrammar(grammarDetail, grammarPhraseOffset, false);
2029#endif
2030    }
2031
2032    // 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
2033    // block rather than at a selection).
2034    if (startedWithSelection && !misspelledWord && !badGrammarPhrase) {
2035        spellingSearchRange->setStart(topNode, 0, IGNORE_EXCEPTION);
2036        // going until the end of the very first chunk we tested is far enough
2037        spellingSearchRange->setEnd(searchEndNodeAfterWrap, searchEndOffsetAfterWrap, IGNORE_EXCEPTION);
2038
2039        if (unifiedTextCheckerEnabled()) {
2040            grammarSearchRange = spellingSearchRange->cloneRange(IGNORE_EXCEPTION);
2041            foundItem = TextCheckingHelper(client(), spellingSearchRange).findFirstMisspellingOrBadGrammar(isGrammarCheckingEnabled(), isSpelling, foundOffset, grammarDetail);
2042            if (isSpelling) {
2043                misspelledWord = foundItem;
2044                misspellingOffset = foundOffset;
2045            } else {
2046                badGrammarPhrase = foundItem;
2047                grammarPhraseOffset = foundOffset;
2048            }
2049        } else {
2050            misspelledWord = TextCheckingHelper(client(), spellingSearchRange).findFirstMisspelling(misspellingOffset, false, firstMisspellingRange);
2051
2052#if USE(GRAMMAR_CHECKING)
2053            grammarSearchRange = spellingSearchRange->cloneRange(IGNORE_EXCEPTION);
2054            if (!misspelledWord.isEmpty()) {
2055                // Stop looking at start of next misspelled word
2056                CharacterIterator chars(*grammarSearchRange);
2057                chars.advance(misspellingOffset);
2058                grammarSearchRange->setEnd(chars.range()->startContainer(), chars.range()->startOffset(), IGNORE_EXCEPTION);
2059            }
2060
2061            if (isGrammarCheckingEnabled())
2062                badGrammarPhrase = TextCheckingHelper(client(), grammarSearchRange).findFirstBadGrammar(grammarDetail, grammarPhraseOffset, false);
2063#endif
2064        }
2065    }
2066
2067#if !USE(GRAMMAR_CHECKING)
2068    ASSERT(badGrammarPhrase.isEmpty());
2069    UNUSED_PARAM(grammarPhraseOffset);
2070#else
2071    if (!badGrammarPhrase.isEmpty()) {
2072        // We found bad grammar. Since we only searched for bad grammar up to the first misspelled word, the bad grammar
2073        // takes precedence and we ignore any potential misspelled word. Select the grammar detail, update the spelling
2074        // panel, and store a marker so we draw the green squiggle later.
2075
2076        ASSERT(badGrammarPhrase.length() > 0);
2077        ASSERT(grammarDetail.location != -1 && grammarDetail.length > 0);
2078
2079        // FIXME 4859190: This gets confused with doubled punctuation at the end of a paragraph
2080        RefPtr<Range> badGrammarRange = TextIterator::subrange(grammarSearchRange.get(), grammarPhraseOffset + grammarDetail.location, grammarDetail.length);
2081        m_frame.selection().setSelection(VisibleSelection(badGrammarRange.get(), SEL_DEFAULT_AFFINITY));
2082        m_frame.selection().revealSelection();
2083
2084        client()->updateSpellingUIWithGrammarString(badGrammarPhrase, grammarDetail);
2085        document().markers().addMarker(badGrammarRange.get(), DocumentMarker::Grammar, grammarDetail.userDescription);
2086    } else
2087#endif
2088    if (!misspelledWord.isEmpty()) {
2089        // We found a misspelling, but not any earlier bad grammar. Select the misspelling, update the spelling panel, and store
2090        // a marker so we draw the red squiggle later.
2091
2092        RefPtr<Range> misspellingRange = TextIterator::subrange(spellingSearchRange.get(), misspellingOffset, misspelledWord.length());
2093        m_frame.selection().setSelection(VisibleSelection(misspellingRange.get(), DOWNSTREAM));
2094        m_frame.selection().revealSelection();
2095
2096        client()->updateSpellingUIWithMisspelledWord(misspelledWord);
2097        document().markers().addMarker(misspellingRange.get(), DocumentMarker::Spelling);
2098    }
2099}
2100#endif // !PLATFORM(IOS)
2101
2102String Editor::misspelledWordAtCaretOrRange(Node* clickedNode) const
2103{
2104    if (!isContinuousSpellCheckingEnabled() || !clickedNode || !isSpellCheckingEnabledFor(clickedNode))
2105        return String();
2106
2107    VisibleSelection selection = m_frame.selection().selection();
2108    if (!selection.isContentEditable() || selection.isNone())
2109        return String();
2110
2111    VisibleSelection wordSelection(selection.base());
2112    wordSelection.expandUsingGranularity(WordGranularity);
2113    RefPtr<Range> wordRange = wordSelection.toNormalizedRange();
2114
2115    // In compliance with GTK+ applications, additionally allow to provide suggestions when the current
2116    // selection exactly match the word selection.
2117    if (selection.isRange() && !areRangesEqual(wordRange.get(), selection.toNormalizedRange().get()))
2118        return String();
2119
2120    String word = wordRange->text();
2121    if (word.isEmpty() || !client())
2122        return String();
2123
2124    int wordLength = word.length();
2125    int misspellingLocation = -1;
2126    int misspellingLength = 0;
2127    textChecker()->checkSpellingOfString(word, &misspellingLocation, &misspellingLength);
2128
2129    return misspellingLength == wordLength ? word : String();
2130}
2131
2132String Editor::misspelledSelectionString() const
2133{
2134    String selectedString = selectedText();
2135    int length = selectedString.length();
2136    if (!length || !client())
2137        return String();
2138
2139    int misspellingLocation = -1;
2140    int misspellingLength = 0;
2141    textChecker()->checkSpellingOfString(selectedString, &misspellingLocation, &misspellingLength);
2142
2143    // The selection only counts as misspelled if the selected text is exactly one misspelled word
2144    if (misspellingLength != length)
2145        return String();
2146
2147    // Update the spelling panel to be displaying this error (whether or not the spelling panel is on screen).
2148    // This is necessary to make a subsequent call to [NSSpellChecker ignoreWord:inSpellDocumentWithTag:] work
2149    // correctly; that call behaves differently based on whether the spelling panel is displaying a misspelling
2150    // or a grammar error.
2151    client()->updateSpellingUIWithMisspelledWord(selectedString);
2152
2153    return selectedString;
2154}
2155
2156bool Editor::isSelectionUngrammatical()
2157{
2158#if USE(GRAMMAR_CHECKING)
2159    RefPtr<Range> range = m_frame.selection().toNormalizedRange();
2160    if (!range)
2161        return false;
2162    return TextCheckingHelper(client(), range).isUngrammatical();
2163#else
2164    return false;
2165#endif
2166}
2167
2168Vector<String> Editor::guessesForMisspelledWord(const String& word) const
2169{
2170    ASSERT(word.length());
2171
2172    Vector<String> guesses;
2173    if (client())
2174        textChecker()->getGuessesForWord(word, String(), guesses);
2175    return guesses;
2176}
2177
2178Vector<String> Editor::guessesForMisspelledOrUngrammatical(bool& misspelled, bool& ungrammatical)
2179{
2180    if (unifiedTextCheckerEnabled()) {
2181        RefPtr<Range> range;
2182        VisibleSelection selection = m_frame.selection().selection();
2183        if (selection.isCaret() && behavior().shouldAllowSpellingSuggestionsWithoutSelection()) {
2184            VisibleSelection wordSelection = VisibleSelection(selection.base());
2185            wordSelection.expandUsingGranularity(WordGranularity);
2186            range = wordSelection.toNormalizedRange();
2187        } else
2188            range = selection.toNormalizedRange();
2189        if (!range)
2190            return Vector<String>();
2191        return TextCheckingHelper(client(), range).guessesForMisspelledOrUngrammaticalRange(isGrammarCheckingEnabled(), misspelled, ungrammatical);
2192    }
2193
2194    String misspelledWord = behavior().shouldAllowSpellingSuggestionsWithoutSelection() ? misspelledWordAtCaretOrRange(document().focusedElement()) : misspelledSelectionString();
2195    misspelled = !misspelledWord.isEmpty();
2196    // Only unified text checker supports guesses for ungrammatical phrases.
2197    ungrammatical = false;
2198
2199    if (misspelled)
2200        return guessesForMisspelledWord(misspelledWord);
2201    return Vector<String>();
2202}
2203
2204void Editor::showSpellingGuessPanel()
2205{
2206    if (!client()) {
2207        LOG_ERROR("No NSSpellChecker");
2208        return;
2209    }
2210
2211    if (client()->spellingUIIsShowing()) {
2212        client()->showSpellingUI(false);
2213        return;
2214    }
2215
2216#if !PLATFORM(IOS)
2217    advanceToNextMisspelling(true);
2218#endif
2219    client()->showSpellingUI(true);
2220}
2221
2222bool Editor::spellingPanelIsShowing()
2223{
2224    if (!client())
2225        return false;
2226    return client()->spellingUIIsShowing();
2227}
2228
2229void Editor::clearMisspellingsAndBadGrammar(const VisibleSelection &movingSelection)
2230{
2231    RefPtr<Range> selectedRange = movingSelection.toNormalizedRange();
2232    if (selectedRange) {
2233        document().markers().removeMarkers(selectedRange.get(), DocumentMarker::Spelling);
2234        document().markers().removeMarkers(selectedRange.get(), DocumentMarker::Grammar);
2235    }
2236}
2237
2238void Editor::markMisspellingsAndBadGrammar(const VisibleSelection &movingSelection)
2239{
2240    markMisspellingsAndBadGrammar(movingSelection, isContinuousSpellCheckingEnabled() && isGrammarCheckingEnabled(), movingSelection);
2241}
2242
2243void Editor::markMisspellingsAfterTypingToWord(const VisiblePosition &wordStart, const VisibleSelection& selectionAfterTyping, bool doReplacement)
2244{
2245#if PLATFORM(IOS)
2246    UNUSED_PARAM(selectionAfterTyping);
2247    UNUSED_PARAM(doReplacement);
2248    TextCheckingTypeMask textCheckingOptions = 0;
2249    if (isContinuousSpellCheckingEnabled())
2250        textCheckingOptions |= TextCheckingTypeSpelling;
2251    if (!(textCheckingOptions & TextCheckingTypeSpelling))
2252        return;
2253
2254    VisibleSelection adjacentWords = VisibleSelection(startOfWord(wordStart, LeftWordIfOnBoundary), endOfWord(wordStart, RightWordIfOnBoundary));
2255    markAllMisspellingsAndBadGrammarInRanges(textCheckingOptions, adjacentWords.toNormalizedRange().get(), adjacentWords.toNormalizedRange().get());
2256#else
2257#if !USE(AUTOMATIC_TEXT_REPLACEMENT)
2258    UNUSED_PARAM(doReplacement);
2259#endif
2260
2261    if (unifiedTextCheckerEnabled()) {
2262        m_alternativeTextController->applyPendingCorrection(selectionAfterTyping);
2263
2264        TextCheckingTypeMask textCheckingOptions = 0;
2265
2266        if (isContinuousSpellCheckingEnabled())
2267            textCheckingOptions |= TextCheckingTypeSpelling;
2268
2269#if USE(AUTOMATIC_TEXT_REPLACEMENT)
2270        if (doReplacement
2271            && (isAutomaticQuoteSubstitutionEnabled()
2272                || isAutomaticLinkDetectionEnabled()
2273                || isAutomaticDashSubstitutionEnabled()
2274                || isAutomaticTextReplacementEnabled()
2275                || ((textCheckingOptions & TextCheckingTypeSpelling) && isAutomaticSpellingCorrectionEnabled())))
2276            textCheckingOptions |= TextCheckingTypeReplacement;
2277#endif
2278        if (!(textCheckingOptions & (TextCheckingTypeSpelling | TextCheckingTypeReplacement)))
2279            return;
2280
2281        if (isGrammarCheckingEnabled())
2282            textCheckingOptions |= TextCheckingTypeGrammar;
2283
2284        VisibleSelection adjacentWords = VisibleSelection(startOfWord(wordStart, LeftWordIfOnBoundary), endOfWord(wordStart, RightWordIfOnBoundary));
2285        if (textCheckingOptions & TextCheckingTypeGrammar) {
2286            VisibleSelection selectedSentence = VisibleSelection(startOfSentence(wordStart), endOfSentence(wordStart));
2287            markAllMisspellingsAndBadGrammarInRanges(textCheckingOptions, adjacentWords.toNormalizedRange().get(), selectedSentence.toNormalizedRange().get());
2288        } else
2289            markAllMisspellingsAndBadGrammarInRanges(textCheckingOptions, adjacentWords.toNormalizedRange().get(), adjacentWords.toNormalizedRange().get());
2290        return;
2291    }
2292
2293    if (!isContinuousSpellCheckingEnabled())
2294        return;
2295
2296    // Check spelling of one word
2297    RefPtr<Range> misspellingRange;
2298    markMisspellings(VisibleSelection(startOfWord(wordStart, LeftWordIfOnBoundary), endOfWord(wordStart, RightWordIfOnBoundary)), misspellingRange);
2299
2300    // Autocorrect the misspelled word.
2301    if (!misspellingRange)
2302        return;
2303
2304    // Get the misspelled word.
2305    const String misspelledWord = plainText(misspellingRange.get());
2306    String autocorrectedString = textChecker()->getAutoCorrectSuggestionForMisspelledWord(misspelledWord);
2307
2308    // If autocorrected word is non empty, replace the misspelled word by this word.
2309    if (!autocorrectedString.isEmpty()) {
2310        VisibleSelection newSelection(misspellingRange.get(), DOWNSTREAM);
2311        if (newSelection != m_frame.selection().selection()) {
2312            if (!m_frame.selection().shouldChangeSelection(newSelection))
2313                return;
2314            m_frame.selection().setSelection(newSelection);
2315        }
2316
2317        if (!m_frame.editor().shouldInsertText(autocorrectedString, misspellingRange.get(), EditorInsertActionTyped))
2318            return;
2319        m_frame.editor().replaceSelectionWithText(autocorrectedString, false, false);
2320
2321        // Reset the charet one character further.
2322        m_frame.selection().moveTo(m_frame.selection().selection().end());
2323        m_frame.selection().modify(FrameSelection::AlterationMove, DirectionForward, CharacterGranularity);
2324    }
2325
2326    if (!isGrammarCheckingEnabled())
2327        return;
2328
2329    // Check grammar of entire sentence
2330    markBadGrammar(VisibleSelection(startOfSentence(wordStart), endOfSentence(wordStart)));
2331#endif
2332}
2333
2334void Editor::markMisspellingsOrBadGrammar(const VisibleSelection& selection, bool checkSpelling, RefPtr<Range>& firstMisspellingRange)
2335{
2336#if !PLATFORM(IOS)
2337    // This function is called with a selection already expanded to word boundaries.
2338    // Might be nice to assert that here.
2339
2340    // This function is used only for as-you-type checking, so if that's off we do nothing. Note that
2341    // grammar checking can only be on if spell checking is also on.
2342    if (!isContinuousSpellCheckingEnabled())
2343        return;
2344
2345    RefPtr<Range> searchRange(selection.toNormalizedRange());
2346    if (!searchRange)
2347        return;
2348
2349    // If we're not in an editable node, bail.
2350    Node* editableNode = searchRange->startContainer();
2351    if (!editableNode || !editableNode->hasEditableStyle())
2352        return;
2353
2354    if (!isSpellCheckingEnabledFor(editableNode))
2355        return;
2356
2357    // Get the spell checker if it is available
2358    if (!client())
2359        return;
2360
2361    TextCheckingHelper checker(client(), searchRange);
2362    if (checkSpelling)
2363        checker.markAllMisspellings(firstMisspellingRange);
2364    else {
2365#if USE(GRAMMAR_CHECKING)
2366        if (isGrammarCheckingEnabled())
2367            checker.markAllBadGrammar();
2368#else
2369        ASSERT_NOT_REACHED();
2370#endif
2371    }
2372#else
2373        UNUSED_PARAM(selection);
2374        UNUSED_PARAM(checkSpelling);
2375        UNUSED_PARAM(firstMisspellingRange);
2376#endif // !PLATFORM(IOS)
2377}
2378
2379bool Editor::isSpellCheckingEnabledFor(Node* node) const
2380{
2381    if (!node)
2382        return false;
2383    const Element* focusedElement = node->isElementNode() ? toElement(node) : node->parentElement();
2384    if (!focusedElement)
2385        return false;
2386    return focusedElement->isSpellCheckingEnabled();
2387}
2388
2389bool Editor::isSpellCheckingEnabledInFocusedNode() const
2390{
2391    return isSpellCheckingEnabledFor(m_frame.selection().selection().start().deprecatedNode());
2392}
2393
2394void Editor::markMisspellings(const VisibleSelection& selection, RefPtr<Range>& firstMisspellingRange)
2395{
2396    markMisspellingsOrBadGrammar(selection, true, firstMisspellingRange);
2397}
2398
2399void Editor::markBadGrammar(const VisibleSelection& selection)
2400{
2401#if USE(GRAMMAR_CHECKING)
2402    RefPtr<Range> firstMisspellingRange;
2403    markMisspellingsOrBadGrammar(selection, false, firstMisspellingRange);
2404#else
2405    ASSERT_NOT_REACHED();
2406#endif
2407}
2408
2409void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingTypeMask textCheckingOptions, Range* spellingRange, Range* grammarRange)
2410{
2411    ASSERT(unifiedTextCheckerEnabled());
2412
2413    // There shouldn't be pending autocorrection at this moment.
2414    ASSERT(!m_alternativeTextController->hasPendingCorrection());
2415
2416    bool shouldMarkGrammar = textCheckingOptions & TextCheckingTypeGrammar;
2417    bool shouldShowCorrectionPanel = textCheckingOptions & TextCheckingTypeShowCorrectionPanel;
2418
2419    // This function is called with selections already expanded to word boundaries.
2420    if (!client() || !spellingRange || (shouldMarkGrammar && !grammarRange))
2421        return;
2422
2423    // If we're not in an editable node, bail.
2424    Node* editableNode = spellingRange->startContainer();
2425    if (!editableNode || !editableNode->hasEditableStyle())
2426        return;
2427
2428    if (!isSpellCheckingEnabledFor(editableNode))
2429        return;
2430
2431    Range* rangeToCheck = shouldMarkGrammar ? grammarRange : spellingRange;
2432    TextCheckingParagraph paragraphToCheck(rangeToCheck);
2433    if (paragraphToCheck.isRangeEmpty() || paragraphToCheck.isEmpty())
2434        return;
2435    RefPtr<Range> paragraphRange = paragraphToCheck.paragraphRange();
2436
2437    bool asynchronous = m_frame.settings().asynchronousSpellCheckingEnabled() && !shouldShowCorrectionPanel;
2438
2439    // In asynchronous mode, we intentionally check paragraph-wide sentence.
2440    RefPtr<SpellCheckRequest> request = SpellCheckRequest::create(resolveTextCheckingTypeMask(textCheckingOptions), TextCheckingProcessIncremental, asynchronous ? paragraphRange : rangeToCheck, paragraphRange);
2441
2442    if (asynchronous) {
2443        m_spellChecker->requestCheckingFor(request.release());
2444        return;
2445    }
2446
2447    Vector<TextCheckingResult> results;
2448    checkTextOfParagraph(*textChecker(), paragraphToCheck.text(), resolveTextCheckingTypeMask(textCheckingOptions), results);
2449    markAndReplaceFor(request.release(), results);
2450}
2451
2452static bool isAutomaticTextReplacementType(TextCheckingType type)
2453{
2454    switch (type) {
2455    case TextCheckingTypeNone:
2456    case TextCheckingTypeSpelling:
2457    case TextCheckingTypeGrammar:
2458        return false;
2459    case TextCheckingTypeLink:
2460    case TextCheckingTypeQuote:
2461    case TextCheckingTypeDash:
2462    case TextCheckingTypeReplacement:
2463    case TextCheckingTypeCorrection:
2464    case TextCheckingTypeShowCorrectionPanel:
2465        return true;
2466    }
2467    ASSERT_NOT_REACHED();
2468    return false;
2469}
2470
2471static void correctSpellcheckingPreservingTextCheckingParagraph(TextCheckingParagraph& paragraph, PassRefPtr<Range> rangeToReplace, const String& replacement, int resultLocation, int resultLength)
2472{
2473    ContainerNode* scope = toContainerNode(highestAncestor(paragraph.paragraphRange()->startContainer()));
2474
2475    size_t paragraphLocation;
2476    size_t paragraphLength;
2477    TextIterator::getLocationAndLengthFromRange(scope, paragraph.paragraphRange().get(), paragraphLocation, paragraphLength);
2478
2479    applyCommand(SpellingCorrectionCommand::create(rangeToReplace, replacement));
2480
2481    // TextCheckingParagraph may be orphaned after SpellingCorrectionCommand mutated DOM.
2482    // See <rdar://10305315>, http://webkit.org/b/89526.
2483
2484    RefPtr<Range> newParagraphRange = TextIterator::rangeFromLocationAndLength(scope, paragraphLocation, paragraphLength + replacement.length() - resultLength);
2485
2486    paragraph = TextCheckingParagraph(TextIterator::subrange(newParagraphRange.get(), resultLocation, replacement.length()), newParagraphRange);
2487}
2488
2489void Editor::markAndReplaceFor(PassRefPtr<SpellCheckRequest> request, const Vector<TextCheckingResult>& results)
2490{
2491    ASSERT(request);
2492
2493    TextCheckingTypeMask textCheckingOptions = request->data().mask();
2494    TextCheckingParagraph paragraph(request->checkingRange(), request->paragraphRange());
2495
2496    const bool shouldMarkSpelling = textCheckingOptions & TextCheckingTypeSpelling;
2497    const bool shouldMarkGrammar = textCheckingOptions & TextCheckingTypeGrammar;
2498    const bool shouldMarkLink = textCheckingOptions & TextCheckingTypeLink;
2499    const bool shouldPerformReplacement = textCheckingOptions & TextCheckingTypeReplacement;
2500    const bool shouldShowCorrectionPanel = textCheckingOptions & TextCheckingTypeShowCorrectionPanel;
2501    const bool shouldCheckForCorrection = shouldShowCorrectionPanel || (textCheckingOptions & TextCheckingTypeCorrection);
2502#if !USE(AUTOCORRECTION_PANEL)
2503    ASSERT(!shouldShowCorrectionPanel);
2504#endif
2505
2506    // Expand the range to encompass entire paragraphs, since text checking needs that much context.
2507    int selectionOffset = 0;
2508    bool useAmbiguousBoundaryOffset = false;
2509    bool selectionChanged = false;
2510    bool restoreSelectionAfterChange = false;
2511    bool adjustSelectionForParagraphBoundaries = false;
2512
2513    if (shouldPerformReplacement || shouldMarkSpelling || shouldCheckForCorrection) {
2514        if (m_frame.selection().selection().selectionType() == VisibleSelection::CaretSelection) {
2515            // Attempt to save the caret position so we can restore it later if needed
2516            Position caretPosition = m_frame.selection().selection().end();
2517            selectionOffset = paragraph.offsetTo(caretPosition, ASSERT_NO_EXCEPTION);
2518            restoreSelectionAfterChange = true;
2519            if (selectionOffset > 0 && (selectionOffset > paragraph.textLength() || paragraph.textCharAt(selectionOffset - 1) == newlineCharacter))
2520                adjustSelectionForParagraphBoundaries = true;
2521            if (selectionOffset > 0 && selectionOffset <= paragraph.textLength() && isAmbiguousBoundaryCharacter(paragraph.textCharAt(selectionOffset - 1)))
2522                useAmbiguousBoundaryOffset = true;
2523        }
2524    }
2525
2526    int offsetDueToReplacement = 0;
2527
2528    for (unsigned i = 0; i < results.size(); i++) {
2529        const int spellingRangeEndOffset = paragraph.checkingEnd() + offsetDueToReplacement;
2530        const TextCheckingType resultType = results[i].type;
2531        const int resultLocation = results[i].location + offsetDueToReplacement;
2532        const int resultLength = results[i].length;
2533        const int resultEndLocation = resultLocation + resultLength;
2534        const String& replacement = results[i].replacement;
2535        const bool resultEndsAtAmbiguousBoundary = useAmbiguousBoundaryOffset && resultEndLocation == selectionOffset - 1;
2536
2537        // Only mark misspelling if:
2538        // 1. Current text checking isn't done for autocorrection, in which case shouldMarkSpelling is false.
2539        // 2. Result falls within spellingRange.
2540        // 3. The word in question doesn't end at an ambiguous boundary. For instance, we would not mark
2541        //    "wouldn'" as misspelled right after apostrophe is typed.
2542        if (shouldMarkSpelling && !shouldShowCorrectionPanel && resultType == TextCheckingTypeSpelling
2543            && resultLocation >= paragraph.checkingStart() && resultEndLocation <= spellingRangeEndOffset && !resultEndsAtAmbiguousBoundary) {
2544            ASSERT(resultLength > 0 && resultLocation >= 0);
2545            RefPtr<Range> misspellingRange = paragraph.subrange(resultLocation, resultLength);
2546            if (!m_alternativeTextController->isSpellingMarkerAllowed(misspellingRange))
2547                continue;
2548            misspellingRange->startContainer()->document().markers().addMarker(misspellingRange.get(), DocumentMarker::Spelling, replacement);
2549        } else if (shouldMarkGrammar && resultType == TextCheckingTypeGrammar && paragraph.checkingRangeCovers(resultLocation, resultLength)) {
2550            ASSERT(resultLength > 0 && resultLocation >= 0);
2551            const Vector<GrammarDetail>& details = results[i].details;
2552            for (unsigned j = 0; j < details.size(); j++) {
2553                const GrammarDetail& detail = details[j];
2554                ASSERT(detail.length > 0 && detail.location >= 0);
2555                if (paragraph.checkingRangeCovers(resultLocation + detail.location, detail.length)) {
2556                    RefPtr<Range> badGrammarRange = paragraph.subrange(resultLocation + detail.location, detail.length);
2557                    badGrammarRange->startContainer()->document().markers().addMarker(badGrammarRange.get(), DocumentMarker::Grammar, detail.userDescription);
2558                }
2559            }
2560        } else if (resultEndLocation <= spellingRangeEndOffset && resultEndLocation >= paragraph.checkingStart()
2561            && isAutomaticTextReplacementType(resultType)) {
2562            // In this case the result range just has to touch the spelling range, so we can handle replacing non-word text such as punctuation.
2563            ASSERT(resultLength > 0 && resultLocation >= 0);
2564
2565            if (shouldShowCorrectionPanel && (resultEndLocation < spellingRangeEndOffset
2566                || !(resultType & (TextCheckingTypeReplacement | TextCheckingTypeCorrection))))
2567                continue;
2568
2569            // Apply replacement if:
2570            // 1. The replacement length is non-zero.
2571            // 2. The result doesn't end at an ambiguous boundary.
2572            //    (FIXME: this is required until 6853027 is fixed and text checking can do this for us
2573            bool doReplacement = replacement.length() > 0 && !resultEndsAtAmbiguousBoundary;
2574            RefPtr<Range> rangeToReplace = paragraph.subrange(resultLocation, resultLength);
2575
2576            // adding links should be done only immediately after they are typed
2577            if (resultType == TextCheckingTypeLink && selectionOffset != resultEndLocation + 1)
2578                continue;
2579
2580            if (!(shouldPerformReplacement || shouldCheckForCorrection || shouldMarkLink) || !doReplacement)
2581                continue;
2582
2583            String replacedString = plainText(rangeToReplace.get());
2584            const bool existingMarkersPermitReplacement = m_alternativeTextController->processMarkersOnTextToBeReplacedByResult(&results[i], rangeToReplace.get(), replacedString);
2585            if (!existingMarkersPermitReplacement)
2586                continue;
2587
2588            if (shouldShowCorrectionPanel) {
2589                if (resultEndLocation == spellingRangeEndOffset) {
2590                    // We only show the correction panel on the last word.
2591                    m_alternativeTextController->show(rangeToReplace, replacement);
2592                    break;
2593                }
2594                // If this function is called for showing correction panel, we ignore other correction or replacement.
2595                continue;
2596            }
2597
2598            VisibleSelection selectionToReplace(rangeToReplace.get(), DOWNSTREAM);
2599            if (selectionToReplace != m_frame.selection().selection()) {
2600                if (!m_frame.selection().shouldChangeSelection(selectionToReplace))
2601                    continue;
2602            }
2603
2604            if (resultType == TextCheckingTypeLink) {
2605                m_frame.selection().setSelection(selectionToReplace);
2606                selectionChanged = true;
2607                restoreSelectionAfterChange = false;
2608                if (canEditRichly())
2609                    applyCommand(CreateLinkCommand::create(document(), replacement));
2610            } else if (canEdit() && shouldInsertText(replacement, rangeToReplace.get(), EditorInsertActionTyped)) {
2611                correctSpellcheckingPreservingTextCheckingParagraph(paragraph, rangeToReplace, replacement, resultLocation, resultLength);
2612
2613                if (AXObjectCache* cache = document().existingAXObjectCache()) {
2614                    if (Element* root = m_frame.selection().selection().rootEditableElement())
2615                        cache->postNotification(root, AXObjectCache::AXAutocorrectionOccured);
2616                }
2617
2618                // Skip all other results for the replaced text.
2619                while (i + 1 < results.size() && results[i + 1].location + offsetDueToReplacement <= resultLocation)
2620                    i++;
2621
2622                selectionChanged = true;
2623                offsetDueToReplacement += replacement.length() - resultLength;
2624                if (resultLocation < selectionOffset)
2625                    selectionOffset += replacement.length() - resultLength;
2626
2627                // Add a marker so that corrections can easily be undone and won't be re-corrected.
2628                if (resultType == TextCheckingTypeCorrection)
2629                    m_alternativeTextController->markCorrection(paragraph.subrange(resultLocation, replacement.length()), replacedString);
2630            }
2631        }
2632    }
2633
2634    if (selectionChanged) {
2635        TextCheckingParagraph extendedParagraph(paragraph);
2636        // Restore the caret position if we have made any replacements
2637        extendedParagraph.expandRangeToNextEnd();
2638        if (restoreSelectionAfterChange && selectionOffset >= 0 && selectionOffset <= extendedParagraph.rangeLength()) {
2639            RefPtr<Range> selectionRange = extendedParagraph.subrange(0, selectionOffset);
2640            m_frame.selection().moveTo(selectionRange->endPosition(), DOWNSTREAM);
2641            if (adjustSelectionForParagraphBoundaries)
2642                m_frame.selection().modify(FrameSelection::AlterationMove, DirectionForward, CharacterGranularity);
2643        } else {
2644            // If this fails for any reason, the fallback is to go one position beyond the last replacement
2645            m_frame.selection().moveTo(m_frame.selection().selection().end());
2646            m_frame.selection().modify(FrameSelection::AlterationMove, DirectionForward, CharacterGranularity);
2647        }
2648    }
2649}
2650
2651void Editor::changeBackToReplacedString(const String& replacedString)
2652{
2653#if !PLATFORM(IOS)
2654    ASSERT(unifiedTextCheckerEnabled());
2655
2656    if (replacedString.isEmpty())
2657        return;
2658
2659    RefPtr<Range> selection = selectedRange();
2660    if (!shouldInsertText(replacedString, selection.get(), EditorInsertActionPasted))
2661        return;
2662
2663    m_alternativeTextController->recordAutocorrectionResponseReversed(replacedString, selection);
2664    TextCheckingParagraph paragraph(selection);
2665    replaceSelectionWithText(replacedString, false, false);
2666    RefPtr<Range> changedRange = paragraph.subrange(paragraph.checkingStart(), replacedString.length());
2667    changedRange->startContainer()->document().markers().addMarker(changedRange.get(), DocumentMarker::Replacement, String());
2668    m_alternativeTextController->markReversed(changedRange.get());
2669#else
2670    ASSERT_NOT_REACHED();
2671    UNUSED_PARAM(replacedString);
2672#endif // !PLATFORM(IOS)
2673}
2674
2675
2676void Editor::markMisspellingsAndBadGrammar(const VisibleSelection& spellingSelection, bool markGrammar, const VisibleSelection& grammarSelection)
2677{
2678    if (unifiedTextCheckerEnabled()) {
2679        if (!isContinuousSpellCheckingEnabled())
2680            return;
2681
2682        // markMisspellingsAndBadGrammar() is triggered by selection change, in which case we check spelling and grammar, but don't autocorrect misspellings.
2683        TextCheckingTypeMask textCheckingOptions = TextCheckingTypeSpelling;
2684        if (markGrammar && isGrammarCheckingEnabled())
2685            textCheckingOptions |= TextCheckingTypeGrammar;
2686        markAllMisspellingsAndBadGrammarInRanges(textCheckingOptions, spellingSelection.toNormalizedRange().get(), grammarSelection.toNormalizedRange().get());
2687        return;
2688    }
2689
2690    RefPtr<Range> firstMisspellingRange;
2691    markMisspellings(spellingSelection, firstMisspellingRange);
2692    if (markGrammar)
2693        markBadGrammar(grammarSelection);
2694}
2695
2696void Editor::unappliedSpellCorrection(const VisibleSelection& selectionOfCorrected, const String& corrected, const String& correction)
2697{
2698    m_alternativeTextController->respondToUnappliedSpellCorrection(selectionOfCorrected, corrected, correction);
2699}
2700
2701void Editor::updateMarkersForWordsAffectedByEditing(bool doNotRemoveIfSelectionAtWordBoundary)
2702{
2703    if (!document().markers().hasMarkers())
2704        return;
2705
2706    if (!m_alternativeTextController->shouldRemoveMarkersUponEditing() && (!textChecker() || textChecker()->shouldEraseMarkersAfterChangeSelection(TextCheckingTypeSpelling)))
2707        return;
2708
2709    // We want to remove the markers from a word if an editing command will change the word. This can happen in one of
2710    // several scenarios:
2711    // 1. Insert in the middle of a word.
2712    // 2. Appending non whitespace at the beginning of word.
2713    // 3. Appending non whitespace at the end of word.
2714    // Note that, appending only whitespaces at the beginning or end of word won't change the word, so we don't need to
2715    // remove the markers on that word.
2716    // Of course, if current selection is a range, we potentially will edit two words that fall on the boundaries of
2717    // selection, and remove words between the selection boundaries.
2718    //
2719    VisiblePosition startOfSelection = m_frame.selection().selection().start();
2720    VisiblePosition endOfSelection = m_frame.selection().selection().end();
2721    if (startOfSelection.isNull())
2722        return;
2723    // First word is the word that ends after or on the start of selection.
2724    VisiblePosition startOfFirstWord = startOfWord(startOfSelection, LeftWordIfOnBoundary);
2725    VisiblePosition endOfFirstWord = endOfWord(startOfSelection, LeftWordIfOnBoundary);
2726    // Last word is the word that begins before or on the end of selection
2727    VisiblePosition startOfLastWord = startOfWord(endOfSelection, RightWordIfOnBoundary);
2728    VisiblePosition endOfLastWord = endOfWord(endOfSelection, RightWordIfOnBoundary);
2729
2730    if (startOfFirstWord.isNull()) {
2731        startOfFirstWord = startOfWord(startOfSelection, RightWordIfOnBoundary);
2732        endOfFirstWord = endOfWord(startOfSelection, RightWordIfOnBoundary);
2733    }
2734
2735    if (endOfLastWord.isNull()) {
2736        startOfLastWord = startOfWord(endOfSelection, LeftWordIfOnBoundary);
2737        endOfLastWord = endOfWord(endOfSelection, LeftWordIfOnBoundary);
2738    }
2739
2740    // If doNotRemoveIfSelectionAtWordBoundary is true, and first word ends at the start of selection,
2741    // we choose next word as the first word.
2742    if (doNotRemoveIfSelectionAtWordBoundary && endOfFirstWord == startOfSelection) {
2743        startOfFirstWord = nextWordPosition(startOfFirstWord);
2744        endOfFirstWord = endOfWord(startOfFirstWord, RightWordIfOnBoundary);
2745        if (startOfFirstWord == endOfSelection)
2746            return;
2747    }
2748
2749    // If doNotRemoveIfSelectionAtWordBoundary is true, and last word begins at the end of selection,
2750    // we choose previous word as the last word.
2751    if (doNotRemoveIfSelectionAtWordBoundary && startOfLastWord == endOfSelection) {
2752        startOfLastWord = previousWordPosition(startOfLastWord);
2753        endOfLastWord = endOfWord(startOfLastWord, RightWordIfOnBoundary);
2754        if (endOfLastWord == startOfSelection)
2755            return;
2756    }
2757
2758    if (startOfFirstWord.isNull() || endOfFirstWord.isNull() || startOfLastWord.isNull() || endOfLastWord.isNull())
2759        return;
2760
2761    // Now we remove markers on everything between startOfFirstWord and endOfLastWord.
2762    // However, if an autocorrection change a single word to multiple words, we want to remove correction mark from all the
2763    // resulted words even we only edit one of them. For example, assuming autocorrection changes "avantgarde" to "avant
2764    // garde", we will have CorrectionIndicator marker on both words and on the whitespace between them. If we then edit garde,
2765    // we would like to remove the marker from word "avant" and whitespace as well. So we need to get the continous range of
2766    // of marker that contains the word in question, and remove marker on that whole range.
2767    RefPtr<Range> wordRange = Range::create(document(), startOfFirstWord.deepEquivalent(), endOfLastWord.deepEquivalent());
2768
2769    Vector<DocumentMarker*> markers = document().markers().markersInRange(wordRange.get(), DocumentMarker::DictationAlternatives);
2770    for (size_t i = 0; i < markers.size(); ++i)
2771        m_alternativeTextController->removeDictationAlternativesForMarker(markers[i]);
2772
2773#if PLATFORM(IOS)
2774    document().markers().removeMarkers(wordRange.get(), DocumentMarker::Spelling | DocumentMarker::CorrectionIndicator | DocumentMarker::SpellCheckingExemption | DocumentMarker::DictationAlternatives | DocumentMarker::DictationPhraseWithAlternatives, DocumentMarkerController::RemovePartiallyOverlappingMarker);
2775#else
2776    document().markers().removeMarkers(wordRange.get(), DocumentMarker::Spelling | DocumentMarker::Grammar | DocumentMarker::CorrectionIndicator | DocumentMarker::SpellCheckingExemption | DocumentMarker::DictationAlternatives, DocumentMarkerController::RemovePartiallyOverlappingMarker);
2777#endif
2778    document().markers().clearDescriptionOnMarkersIntersectingRange(wordRange.get(), DocumentMarker::Replacement);
2779}
2780
2781void Editor::deletedAutocorrectionAtPosition(const Position& position, const String& originalString)
2782{
2783    m_alternativeTextController->deletedAutocorrectionAtPosition(position, originalString);
2784}
2785
2786PassRefPtr<Range> Editor::rangeForPoint(const IntPoint& windowPoint)
2787{
2788    Document* document = m_frame.documentAtPoint(windowPoint);
2789    if (!document)
2790        return 0;
2791
2792    Frame* frame = document->frame();
2793    ASSERT(frame);
2794    FrameView* frameView = frame->view();
2795    if (!frameView)
2796        return 0;
2797    IntPoint framePoint = frameView->windowToContents(windowPoint);
2798    VisibleSelection selection(frame->visiblePositionForPoint(framePoint));
2799
2800    return avoidIntersectionWithDeleteButtonController(selection.toNormalizedRange().get());
2801}
2802
2803void Editor::revealSelectionAfterEditingOperation(const ScrollAlignment& alignment, RevealExtentOption revealExtentOption)
2804{
2805    if (m_ignoreCompositionSelectionChange)
2806        return;
2807
2808    m_frame.selection().revealSelection(alignment, revealExtentOption);
2809}
2810
2811void Editor::setIgnoreCompositionSelectionChange(bool ignore)
2812{
2813    if (m_ignoreCompositionSelectionChange == ignore)
2814        return;
2815
2816    m_ignoreCompositionSelectionChange = ignore;
2817#if PLATFORM(IOS)
2818    // FIXME: Should suppress selection change notifications during a composition change <https://webkit.org/b/38830>
2819    if (!ignore)
2820        respondToChangedSelection(m_frame.selection().selection(), 0);
2821#endif
2822    if (!ignore)
2823        revealSelectionAfterEditingOperation(ScrollAlignment::alignToEdgeIfNeeded, RevealExtent);
2824}
2825
2826PassRefPtr<Range> Editor::compositionRange() const
2827{
2828    if (!m_compositionNode)
2829        return 0;
2830    unsigned length = m_compositionNode->length();
2831    unsigned start = std::min(m_compositionStart, length);
2832    unsigned end = std::min(std::max(start, m_compositionEnd), length);
2833    if (start >= end)
2834        return 0;
2835    return Range::create(m_compositionNode->document(), m_compositionNode.get(), start, m_compositionNode.get(), end);
2836}
2837
2838bool Editor::getCompositionSelection(unsigned& selectionStart, unsigned& selectionEnd) const
2839{
2840    if (!m_compositionNode)
2841        return false;
2842    const VisibleSelection& selection = m_frame.selection().selection();
2843    Position start = selection.start();
2844    if (start.deprecatedNode() != m_compositionNode)
2845        return false;
2846    Position end = selection.end();
2847    if (end.deprecatedNode() != m_compositionNode)
2848        return false;
2849
2850    if (static_cast<unsigned>(start.deprecatedEditingOffset()) < m_compositionStart)
2851        return false;
2852    if (static_cast<unsigned>(end.deprecatedEditingOffset()) > m_compositionEnd)
2853        return false;
2854
2855    selectionStart = start.deprecatedEditingOffset() - m_compositionStart;
2856    selectionEnd = start.deprecatedEditingOffset() - m_compositionEnd;
2857    return true;
2858}
2859
2860void Editor::transpose()
2861{
2862    if (!canEdit())
2863        return;
2864
2865    VisibleSelection selection = m_frame.selection().selection();
2866    if (!selection.isCaret())
2867        return;
2868
2869    // Make a selection that goes back one character and forward two characters.
2870    VisiblePosition caret = selection.visibleStart();
2871    VisiblePosition next = isEndOfParagraph(caret) ? caret : caret.next();
2872    VisiblePosition previous = next.previous();
2873    if (next == previous)
2874        return;
2875    previous = previous.previous();
2876    if (!inSameParagraph(next, previous))
2877        return;
2878    RefPtr<Range> range = makeRange(previous, next);
2879    if (!range)
2880        return;
2881    VisibleSelection newSelection(range.get(), DOWNSTREAM);
2882
2883    // Transpose the two characters.
2884    String text = plainText(range.get());
2885    if (text.length() != 2)
2886        return;
2887    String transposed = text.right(1) + text.left(1);
2888
2889    // Select the two characters.
2890    if (newSelection != m_frame.selection().selection()) {
2891        if (!m_frame.selection().shouldChangeSelection(newSelection))
2892            return;
2893        m_frame.selection().setSelection(newSelection);
2894    }
2895
2896    // Insert the transposed characters.
2897    if (!shouldInsertText(transposed, range.get(), EditorInsertActionTyped))
2898        return;
2899    replaceSelectionWithText(transposed, false, false);
2900}
2901
2902void Editor::addToKillRing(Range* range, bool prepend)
2903{
2904    if (m_shouldStartNewKillRingSequence)
2905        killRing().startNewSequence();
2906
2907    String text = plainText(range);
2908    if (prepend)
2909        killRing().prepend(text);
2910    else
2911        killRing().append(text);
2912    m_shouldStartNewKillRingSequence = false;
2913}
2914
2915void Editor::startAlternativeTextUITimer()
2916{
2917    m_alternativeTextController->startAlternativeTextUITimer(AlternativeTextTypeCorrection);
2918}
2919
2920void Editor::handleAlternativeTextUIResult(const String& correction)
2921{
2922    m_alternativeTextController->handleAlternativeTextUIResult(correction);
2923}
2924
2925
2926void Editor::dismissCorrectionPanelAsIgnored()
2927{
2928    m_alternativeTextController->dismiss(ReasonForDismissingAlternativeTextIgnored);
2929}
2930
2931void Editor::changeSelectionAfterCommand(const VisibleSelection& newSelection,  FrameSelection::SetSelectionOptions options)
2932{
2933    // If the new selection is orphaned, then don't update the selection.
2934    if (newSelection.start().isOrphan() || newSelection.end().isOrphan())
2935        return;
2936
2937    // If there is no selection change, don't bother sending shouldChangeSelection, but still call setSelection,
2938    // because there is work that it must do in this situation.
2939    // The old selection can be invalid here and calling shouldChangeSelection can produce some strange calls.
2940    // See <rdar://problem/5729315> Some shouldChangeSelectedDOMRange contain Ranges for selections that are no longer valid
2941    bool selectionDidNotChangeDOMPosition = newSelection == m_frame.selection().selection();
2942    if (selectionDidNotChangeDOMPosition || m_frame.selection().shouldChangeSelection(newSelection))
2943        m_frame.selection().setSelection(newSelection, options);
2944
2945    // Some editing operations change the selection visually without affecting its position within the DOM.
2946    // For example when you press return in the following (the caret is marked by ^):
2947    // <div contentEditable="true"><div>^Hello</div></div>
2948    // WebCore inserts <div><br></div> *before* the current block, which correctly moves the paragraph down but which doesn't
2949    // change the caret's DOM position (["hello", 0]). In these situations the above FrameSelection::setSelection call
2950    // does not call EditorClient::respondToChangedSelection(), which, on the Mac, sends selection change notifications and
2951    // starts a new kill ring sequence, but we want to do these things (matches AppKit).
2952#if PLATFORM(IOS)
2953    // FIXME: Should suppress selection change notifications during a composition change <https://webkit.org/b/38830>
2954    if (m_ignoreCompositionSelectionChange)
2955        return;
2956#endif
2957    if (selectionDidNotChangeDOMPosition && client())
2958        client()->respondToChangedSelection(&m_frame);
2959}
2960
2961String Editor::selectedText() const
2962{
2963    return selectedText(TextIteratorDefaultBehavior);
2964}
2965
2966String Editor::selectedTextForDataTransfer() const
2967{
2968    if (m_frame.settings().selectionIncludesAltImageText())
2969        return selectedText(TextIteratorEmitsImageAltText);
2970    return selectedText();
2971}
2972
2973String Editor::selectedText(TextIteratorBehavior behavior) const
2974{
2975    // We remove '\0' characters because they are not visibly rendered to the user.
2976    return plainText(m_frame.selection().toNormalizedRange().get(), behavior).replaceWithLiteral('\0', "");
2977}
2978
2979static inline void collapseCaretWidth(IntRect& rect)
2980{
2981    // FIXME: Width adjustment doesn't work for rotated text.
2982    if (rect.width() == caretWidth)
2983        rect.setWidth(0);
2984    else if (rect.height() == caretWidth)
2985        rect.setHeight(0);
2986}
2987
2988IntRect Editor::firstRectForRange(Range* range) const
2989{
2990    ASSERT(range->startContainer());
2991    ASSERT(range->endContainer());
2992
2993    VisiblePosition startVisiblePosition(range->startPosition(), DOWNSTREAM);
2994
2995    if (range->collapsed(ASSERT_NO_EXCEPTION)) {
2996        // FIXME: Getting caret rect and removing caret width is a very roundabout way to get collapsed range location.
2997        // In particular, width adjustment doesn't work for rotated text.
2998        IntRect startCaretRect = RenderedPosition(startVisiblePosition).absoluteRect();
2999        collapseCaretWidth(startCaretRect);
3000        return startCaretRect;
3001    }
3002
3003    VisiblePosition endVisiblePosition(range->endPosition(), UPSTREAM);
3004
3005    if (inSameLine(startVisiblePosition, endVisiblePosition))
3006        return enclosingIntRect(RenderObject::absoluteBoundingBoxRectForRange(range));
3007
3008    LayoutUnit extraWidthToEndOfLine = 0;
3009    IntRect startCaretRect = RenderedPosition(startVisiblePosition).absoluteRect(&extraWidthToEndOfLine);
3010    if (startCaretRect == IntRect())
3011        return IntRect();
3012
3013    // When start and end aren't on the same line, we want to go from start to the end of its line.
3014    bool textIsHorizontal = startCaretRect.width() == caretWidth;
3015    return textIsHorizontal ?
3016        IntRect(startCaretRect.x(),
3017            startCaretRect.y(),
3018            startCaretRect.width() + extraWidthToEndOfLine,
3019            startCaretRect.height()) :
3020        IntRect(startCaretRect.x(),
3021            startCaretRect.y(),
3022            startCaretRect.width(),
3023            startCaretRect.height() + extraWidthToEndOfLine);
3024}
3025
3026bool Editor::shouldChangeSelection(const VisibleSelection& oldSelection, const VisibleSelection& newSelection, EAffinity affinity, bool stillSelecting) const
3027{
3028#if PLATFORM(IOS)
3029    if (m_frame.selectionChangeCallbacksDisabled())
3030        return true;
3031#endif
3032    return client() && client()->shouldChangeSelectedRange(oldSelection.toNormalizedRange().get(), newSelection.toNormalizedRange().get(), affinity, stillSelecting);
3033}
3034
3035void Editor::computeAndSetTypingStyle(StyleProperties* style, EditAction editingAction)
3036{
3037    if (!style || style->isEmpty()) {
3038        m_frame.selection().clearTypingStyle();
3039        return;
3040    }
3041
3042    // Calculate the current typing style.
3043    RefPtr<EditingStyle> typingStyle;
3044    if (m_frame.selection().typingStyle()) {
3045        typingStyle = m_frame.selection().typingStyle()->copy();
3046        typingStyle->overrideWithStyle(style);
3047    } else
3048        typingStyle = EditingStyle::create(style);
3049
3050    typingStyle->prepareToApplyAt(m_frame.selection().selection().visibleStart().deepEquivalent(), EditingStyle::PreserveWritingDirection);
3051
3052    // Handle block styles, substracting these from the typing style.
3053    RefPtr<EditingStyle> blockStyle = typingStyle->extractAndRemoveBlockProperties();
3054    if (!blockStyle->isEmpty())
3055        applyCommand(ApplyStyleCommand::create(document(), blockStyle.get(), editingAction));
3056
3057    // Set the remaining style as the typing style.
3058    m_frame.selection().setTypingStyle(typingStyle);
3059}
3060
3061void Editor::textFieldDidBeginEditing(Element* e)
3062{
3063    if (client())
3064        client()->textFieldDidBeginEditing(e);
3065}
3066
3067void Editor::textFieldDidEndEditing(Element* e)
3068{
3069    dismissCorrectionPanelAsIgnored();
3070    if (client())
3071        client()->textFieldDidEndEditing(e);
3072}
3073
3074void Editor::textDidChangeInTextField(Element* e)
3075{
3076    if (client())
3077        client()->textDidChangeInTextField(e);
3078}
3079
3080bool Editor::doTextFieldCommandFromEvent(Element* e, KeyboardEvent* ke)
3081{
3082    if (client())
3083        return client()->doTextFieldCommandFromEvent(e, ke);
3084
3085    return false;
3086}
3087
3088void Editor::textWillBeDeletedInTextField(Element* input)
3089{
3090    if (client())
3091        client()->textWillBeDeletedInTextField(input);
3092}
3093
3094void Editor::textDidChangeInTextArea(Element* e)
3095{
3096    if (client())
3097        client()->textDidChangeInTextArea(e);
3098}
3099
3100void Editor::applyEditingStyleToBodyElement() const
3101{
3102    RefPtr<NodeList> list = document().getElementsByTagName("body");
3103    unsigned len = list->length();
3104    for (unsigned i = 0; i < len; i++)
3105        applyEditingStyleToElement(toElement(list->item(i)));
3106}
3107
3108void Editor::applyEditingStyleToElement(Element* element) const
3109{
3110    if (!element)
3111        return;
3112    ASSERT(element->isStyledElement());
3113    if (!element->isStyledElement())
3114        return;
3115
3116    // Mutate using the CSSOM wrapper so we get the same event behavior as a script.
3117    CSSStyleDeclaration* style = toStyledElement(element)->style();
3118    style->setPropertyInternal(CSSPropertyWordWrap, "break-word", false, IGNORE_EXCEPTION);
3119    style->setPropertyInternal(CSSPropertyWebkitNbspMode, "space", false, IGNORE_EXCEPTION);
3120    style->setPropertyInternal(CSSPropertyWebkitLineBreak, "after-white-space", false, IGNORE_EXCEPTION);
3121}
3122
3123bool Editor::findString(const String& target, FindOptions options)
3124{
3125    VisibleSelection selection = m_frame.selection().selection();
3126
3127    RefPtr<Range> resultRange = rangeOfString(target, selection.firstRange().get(), options);
3128
3129    if (!resultRange)
3130        return false;
3131
3132    m_frame.selection().setSelection(VisibleSelection(resultRange.get(), DOWNSTREAM));
3133
3134    if (!(options & DoNotRevealSelection))
3135        m_frame.selection().revealSelection();
3136
3137    return true;
3138}
3139
3140PassRefPtr<Range> Editor::findStringAndScrollToVisible(const String& target, Range* previousMatch, FindOptions options)
3141{
3142    RefPtr<Range> nextMatch = rangeOfString(target, previousMatch, options);
3143    if (!nextMatch)
3144        return 0;
3145
3146    nextMatch->firstNode()->renderer()->scrollRectToVisible(nextMatch->boundingBox(),
3147        ScrollAlignment::alignCenterIfNeeded, ScrollAlignment::alignCenterIfNeeded);
3148
3149    return nextMatch.release();
3150}
3151
3152PassRefPtr<Range> Editor::rangeOfString(const String& target, Range* referenceRange, FindOptions options)
3153{
3154    if (target.isEmpty())
3155        return 0;
3156
3157    // Start from an edge of the reference range, if there's a reference range that's not in shadow content. Which edge
3158    // is used depends on whether we're searching forward or backward, and whether startInSelection is set.
3159    RefPtr<Range> searchRange(rangeOfContents(document()));
3160
3161    bool forward = !(options & Backwards);
3162    bool startInReferenceRange = referenceRange && (options & StartInSelection);
3163    if (referenceRange) {
3164        if (forward)
3165            searchRange->setStart(startInReferenceRange ? referenceRange->startPosition() : referenceRange->endPosition());
3166        else
3167            searchRange->setEnd(startInReferenceRange ? referenceRange->endPosition() : referenceRange->startPosition());
3168    }
3169
3170    RefPtr<Node> shadowTreeRoot = referenceRange && referenceRange->startContainer() ? referenceRange->startContainer()->nonBoundaryShadowTreeRootNode() : 0;
3171    if (shadowTreeRoot) {
3172        if (forward)
3173            searchRange->setEnd(shadowTreeRoot.get(), shadowTreeRoot->childNodeCount());
3174        else
3175            searchRange->setStart(shadowTreeRoot.get(), 0);
3176    }
3177
3178    RefPtr<Range> resultRange(findPlainText(*searchRange, target, options));
3179    // If we started in the reference range and the found range exactly matches the reference range, find again.
3180    // Build a selection with the found range to remove collapsed whitespace.
3181    // Compare ranges instead of selection objects to ignore the way that the current selection was made.
3182    if (startInReferenceRange && areRangesEqual(VisibleSelection(resultRange.get()).toNormalizedRange().get(), referenceRange)) {
3183        searchRange = rangeOfContents(document());
3184        if (forward)
3185            searchRange->setStart(referenceRange->endPosition());
3186        else
3187            searchRange->setEnd(referenceRange->startPosition());
3188
3189        if (shadowTreeRoot) {
3190            if (forward)
3191                searchRange->setEnd(shadowTreeRoot.get(), shadowTreeRoot->childNodeCount());
3192            else
3193                searchRange->setStart(shadowTreeRoot.get(), 0);
3194        }
3195
3196        resultRange = findPlainText(*searchRange, target, options);
3197    }
3198
3199    // If nothing was found in the shadow tree, search in main content following the shadow tree.
3200    if (resultRange->collapsed(ASSERT_NO_EXCEPTION) && shadowTreeRoot) {
3201        searchRange = rangeOfContents(document());
3202        if (forward)
3203            searchRange->setStartAfter(shadowTreeRoot->shadowHost());
3204        else
3205            searchRange->setEndBefore(shadowTreeRoot->shadowHost());
3206
3207        resultRange = findPlainText(*searchRange, target, options);
3208    }
3209
3210    // If we didn't find anything and we're wrapping, search again in the entire document (this will
3211    // redundantly re-search the area already searched in some cases).
3212    if (resultRange->collapsed(ASSERT_NO_EXCEPTION) && options & WrapAround) {
3213        searchRange = rangeOfContents(document());
3214        resultRange = findPlainText(*searchRange, target, options);
3215        // We used to return false here if we ended up with the same range that we started with
3216        // (e.g., the reference range was already the only instance of this text). But we decided that
3217        // this should be a success case instead, so we'll just fall through in that case.
3218    }
3219
3220    return resultRange->collapsed(ASSERT_NO_EXCEPTION) ? 0 : resultRange.release();
3221}
3222
3223static bool isFrameInRange(Frame* frame, Range* range)
3224{
3225    bool inRange = false;
3226    for (HTMLFrameOwnerElement* ownerElement = frame->ownerElement(); ownerElement; ownerElement = ownerElement->document().ownerElement()) {
3227        if (&ownerElement->document() == &range->ownerDocument()) {
3228            inRange = range->intersectsNode(ownerElement, IGNORE_EXCEPTION);
3229            break;
3230        }
3231    }
3232    return inRange;
3233}
3234
3235unsigned Editor::countMatchesForText(const String& target, Range* range, FindOptions options, unsigned limit, bool markMatches, Vector<RefPtr<Range>>* matches)
3236{
3237    if (target.isEmpty())
3238        return 0;
3239
3240    RefPtr<Range> searchRange;
3241    if (range) {
3242        if (&range->ownerDocument() == &document())
3243            searchRange = range;
3244        else if (!isFrameInRange(&m_frame, range))
3245            return 0;
3246    }
3247    if (!searchRange)
3248        searchRange = rangeOfContents(document());
3249
3250    Node* originalEndContainer = searchRange->endContainer();
3251    int originalEndOffset = searchRange->endOffset();
3252
3253    unsigned matchCount = 0;
3254    do {
3255        RefPtr<Range> resultRange(findPlainText(*searchRange, target, options & ~Backwards));
3256        if (resultRange->collapsed(IGNORE_EXCEPTION)) {
3257            if (!resultRange->startContainer()->isInShadowTree())
3258                break;
3259
3260            searchRange->setStartAfter(resultRange->startContainer()->shadowHost(), IGNORE_EXCEPTION);
3261            searchRange->setEnd(originalEndContainer, originalEndOffset, IGNORE_EXCEPTION);
3262            continue;
3263        }
3264
3265        ++matchCount;
3266        if (matches)
3267            matches->append(resultRange);
3268
3269        if (markMatches)
3270            document().markers().addMarker(resultRange.get(), DocumentMarker::TextMatch);
3271
3272        // Stop looking if we hit the specified limit. A limit of 0 means no limit.
3273        if (limit > 0 && matchCount >= limit)
3274            break;
3275
3276        // Set the new start for the search range to be the end of the previous
3277        // result range. There is no need to use a VisiblePosition here,
3278        // since findPlainText will use a TextIterator to go over the visible
3279        // text nodes.
3280        searchRange->setStart(resultRange->endContainer(IGNORE_EXCEPTION), resultRange->endOffset(IGNORE_EXCEPTION), IGNORE_EXCEPTION);
3281
3282        Node* shadowTreeRoot = searchRange->shadowRoot();
3283        if (searchRange->collapsed(IGNORE_EXCEPTION) && shadowTreeRoot)
3284            searchRange->setEnd(shadowTreeRoot, shadowTreeRoot->childNodeCount(), IGNORE_EXCEPTION);
3285    } while (true);
3286
3287    if (markMatches || matches) {
3288        // Do a "fake" paint in order to execute the code that computes the rendered rect for each text match.
3289        if (m_frame.view() && m_frame.contentRenderer()) {
3290            document().updateLayout(); // Ensure layout is up to date.
3291            // FIXME: unclear if we need LegacyIOSDocumentVisibleRect.
3292            // FIXME: this should probably look at paintsEntireContents()
3293            LayoutRect visibleRect = m_frame.view()->visibleContentRect(ScrollableArea::LegacyIOSDocumentVisibleRect);
3294            if (!visibleRect.isEmpty()) {
3295                GraphicsContext context((PlatformGraphicsContext*)0);
3296                context.setPaintingDisabled(true);
3297
3298                PaintBehavior oldBehavior = m_frame.view()->paintBehavior();
3299                m_frame.view()->setPaintBehavior(oldBehavior | PaintBehaviorFlattenCompositingLayers);
3300                m_frame.view()->paintContents(&context, enclosingIntRect(visibleRect));
3301                m_frame.view()->setPaintBehavior(oldBehavior);
3302            }
3303        }
3304    }
3305
3306    return matchCount;
3307}
3308
3309void Editor::setMarkedTextMatchesAreHighlighted(bool flag)
3310{
3311    if (flag == m_areMarkedTextMatchesHighlighted)
3312        return;
3313
3314    m_areMarkedTextMatchesHighlighted = flag;
3315    document().markers().repaintMarkers(DocumentMarker::TextMatch);
3316}
3317
3318void Editor::respondToChangedSelection(const VisibleSelection&, FrameSelection::SetSelectionOptions options)
3319{
3320#if PLATFORM(IOS)
3321    // FIXME: Should suppress selection change notifications during a composition change <https://webkit.org/b/38830>
3322    if (m_ignoreCompositionSelectionChange)
3323        return;
3324#endif
3325
3326    if (client())
3327        client()->respondToChangedSelection(&m_frame);
3328
3329#if ENABLE(TELEPHONE_NUMBER_DETECTION) && !PLATFORM(IOS)
3330    if (shouldDetectTelephoneNumbers())
3331        m_telephoneNumberDetectionUpdateTimer.startOneShot(0);
3332#endif
3333
3334    setStartNewKillRingSequence(true);
3335
3336    if (m_editorUIUpdateTimer.isActive())
3337        return;
3338
3339    // Don't check spelling and grammar if the change of selection is triggered by spelling correction itself.
3340    m_editorUIUpdateTimerShouldCheckSpellingAndGrammar = options & FrameSelection::CloseTyping
3341        && !(options & FrameSelection::SpellCorrectionTriggered);
3342    m_editorUIUpdateTimerWasTriggeredByDictation = options & FrameSelection::DictationTriggered;
3343    m_editorUIUpdateTimer.startOneShot(0);
3344}
3345
3346#if ENABLE(TELEPHONE_NUMBER_DETECTION) && !PLATFORM(IOS)
3347
3348bool Editor::shouldDetectTelephoneNumbers()
3349{
3350    if (!m_frame.document())
3351        return false;
3352    return document().isTelephoneNumberParsingEnabled() && TelephoneNumberDetector::isSupported();
3353}
3354
3355void Editor::scanSelectionForTelephoneNumbers(Timer<Editor>&)
3356{
3357    scanSelectionForTelephoneNumbers();
3358}
3359
3360void Editor::scanSelectionForTelephoneNumbers()
3361{
3362    if (!shouldDetectTelephoneNumbers() || !client())
3363        return;
3364
3365    m_detectedTelephoneNumberRanges.clear();
3366
3367    Vector<RefPtr<Range>> markedRanges;
3368
3369    FrameSelection& frameSelection = m_frame.selection();
3370    if (!frameSelection.isRange()) {
3371        client()->selectedTelephoneNumberRangesChanged();
3372        return;
3373    }
3374    RefPtr<Range> selectedRange = frameSelection.toNormalizedRange();
3375
3376    // Extend the range a few characters in each direction to detect incompletely selected phone numbers.
3377    static const int charactersToExtend = 15;
3378    const VisibleSelection& visibleSelection = frameSelection.selection();
3379    Position start = visibleSelection.start();
3380    Position end = visibleSelection.end();
3381    for (int i = 0; i < charactersToExtend; ++i) {
3382        if (directionOfEnclosingBlock(start) == LTR)
3383            start = start.previous(Character);
3384        else
3385            start = start.next(Character);
3386
3387        if (directionOfEnclosingBlock(end) == LTR)
3388            end = end.next(Character);
3389        else
3390            end = end.previous(Character);
3391    }
3392
3393    FrameSelection extendedSelection;
3394    extendedSelection.setStart(start);
3395    extendedSelection.setEnd(end);
3396    RefPtr<Range> extendedRange = extendedSelection.toNormalizedRange();
3397
3398    if (!extendedRange) {
3399        client()->selectedTelephoneNumberRangesChanged();
3400        return;
3401    }
3402
3403    scanRangeForTelephoneNumbers(*extendedRange, extendedRange->text(), markedRanges);
3404
3405    // Only consider ranges with a detected telephone number if they overlap with the actual selection range.
3406    for (auto& range : markedRanges) {
3407        if (rangesOverlap(range.get(), selectedRange.get()))
3408            m_detectedTelephoneNumberRanges.append(range);
3409    }
3410
3411    client()->selectedTelephoneNumberRangesChanged();
3412}
3413
3414void Editor::scanRangeForTelephoneNumbers(Range& range, const StringView& stringView, Vector<RefPtr<Range>>& markedRanges)
3415{
3416    // Don't scan for phone numbers inside editable regions.
3417    Node* startNode = range.startContainer();
3418    ASSERT(startNode);
3419    if (startNode->hasEditableStyle())
3420        return;
3421
3422    // relativeStartPosition and relativeEndPosition are the endpoints of the phone number range,
3423    // relative to the scannerPosition
3424    unsigned length = stringView.length();
3425    unsigned scannerPosition = 0;
3426    int relativeStartPosition = 0;
3427    int relativeEndPosition = 0;
3428
3429    auto characters = stringView.upconvertedCharacters();
3430
3431    while (scannerPosition < length && TelephoneNumberDetector::find(&characters[scannerPosition], length - scannerPosition, &relativeStartPosition, &relativeEndPosition)) {
3432        // The convention in the Data Detectors framework is that the end position is the first character NOT in the phone number
3433        // (that is, the length of the range is relativeEndPosition - relativeStartPosition). So subtract 1 to get the same
3434        // convention as the old WebCore phone number parser (so that the rest of the code is still valid if we want to go back
3435        // to the old parser).
3436        --relativeEndPosition;
3437
3438        ASSERT(scannerPosition + relativeEndPosition < length);
3439
3440        unsigned subrangeOffset = scannerPosition + relativeStartPosition;
3441        unsigned subrangeLength = relativeEndPosition - relativeStartPosition + 1;
3442
3443        RefPtr<Range> subrange = TextIterator::subrange(&range, subrangeOffset, subrangeLength);
3444
3445        markedRanges.append(subrange);
3446        range.ownerDocument().markers().addMarker(subrange.get(), DocumentMarker::TelephoneNumber);
3447
3448        scannerPosition += relativeEndPosition + 1;
3449    }
3450}
3451
3452#endif // ENABLE(TELEPHONE_NUMBER_DETECTION) && !PLATFORM(IOS)
3453
3454void Editor::updateEditorUINowIfScheduled()
3455{
3456    if (!m_editorUIUpdateTimer.isActive())
3457        return;
3458    m_editorUIUpdateTimer.stop();
3459    editorUIUpdateTimerFired(m_editorUIUpdateTimer);
3460}
3461
3462void Editor::editorUIUpdateTimerFired(Timer<Editor>&)
3463{
3464    VisibleSelection oldSelection = m_oldSelectionForEditorUIUpdate;
3465
3466    m_alternativeTextController->stopPendingCorrection(oldSelection);
3467
3468    bool isContinuousSpellCheckingEnabled = this->isContinuousSpellCheckingEnabled();
3469    bool isContinuousGrammarCheckingEnabled = isContinuousSpellCheckingEnabled && isGrammarCheckingEnabled();
3470    if (isContinuousSpellCheckingEnabled) {
3471        VisibleSelection newAdjacentWords;
3472        VisibleSelection newSelectedSentence;
3473        bool caretBrowsing = m_frame.settings().caretBrowsingEnabled();
3474        if (m_frame.selection().selection().isContentEditable() || caretBrowsing) {
3475            VisiblePosition newStart(m_frame.selection().selection().visibleStart());
3476#if !PLATFORM(IOS)
3477            newAdjacentWords = VisibleSelection(startOfWord(newStart, LeftWordIfOnBoundary), endOfWord(newStart, RightWordIfOnBoundary));
3478#else
3479            // If this bug gets fixed, this PLATFORM(IOS) code could be removed:
3480            // <rdar://problem/7259611> Word boundary code on iPhone gives different results than desktop
3481            EWordSide startWordSide = LeftWordIfOnBoundary;
3482            UChar32 c = newStart.characterBefore();
3483            // FIXME: VisiblePosition::characterAfter() and characterBefore() do not emit newlines the same
3484            // way as TextIterator, so we do an isStartOfParagraph check here.
3485            if (isSpaceOrNewline(c) || c == 0xA0 || isStartOfParagraph(newStart)) {
3486                startWordSide = RightWordIfOnBoundary;
3487            }
3488            newAdjacentWords = VisibleSelection(startOfWord(newStart, startWordSide), endOfWord(newStart, RightWordIfOnBoundary));
3489#endif // !PLATFORM(IOS)
3490            if (isContinuousGrammarCheckingEnabled)
3491                newSelectedSentence = VisibleSelection(startOfSentence(newStart), endOfSentence(newStart));
3492        }
3493
3494        // When typing we check spelling elsewhere, so don't redo it here.
3495        // If this is a change in selection resulting from a delete operation,
3496        // oldSelection may no longer be in the document.
3497        if (m_editorUIUpdateTimerShouldCheckSpellingAndGrammar && oldSelection.isContentEditable() && oldSelection.start().deprecatedNode() && oldSelection.start().anchorNode()->inDocument()) {
3498            VisiblePosition oldStart(oldSelection.visibleStart());
3499            VisibleSelection oldAdjacentWords = VisibleSelection(startOfWord(oldStart, LeftWordIfOnBoundary), endOfWord(oldStart, RightWordIfOnBoundary));
3500            if (oldAdjacentWords != newAdjacentWords) {
3501                if (isContinuousGrammarCheckingEnabled) {
3502                    VisibleSelection oldSelectedSentence = VisibleSelection(startOfSentence(oldStart), endOfSentence(oldStart));
3503                    markMisspellingsAndBadGrammar(oldAdjacentWords, oldSelectedSentence != newSelectedSentence, oldSelectedSentence);
3504                } else
3505                    markMisspellingsAndBadGrammar(oldAdjacentWords, false, oldAdjacentWords);
3506            }
3507        }
3508
3509        if (!textChecker() || textChecker()->shouldEraseMarkersAfterChangeSelection(TextCheckingTypeSpelling)) {
3510            if (RefPtr<Range> wordRange = newAdjacentWords.toNormalizedRange())
3511                document().markers().removeMarkers(wordRange.get(), DocumentMarker::Spelling);
3512        }
3513        if (!textChecker() || textChecker()->shouldEraseMarkersAfterChangeSelection(TextCheckingTypeGrammar)) {
3514            if (RefPtr<Range> sentenceRange = newSelectedSentence.toNormalizedRange())
3515                document().markers().removeMarkers(sentenceRange.get(), DocumentMarker::Grammar);
3516        }
3517    }
3518
3519    // When continuous spell checking is off, existing markers disappear after the selection changes.
3520    if (!isContinuousSpellCheckingEnabled)
3521        document().markers().removeMarkers(DocumentMarker::Spelling);
3522    if (!isContinuousGrammarCheckingEnabled)
3523        document().markers().removeMarkers(DocumentMarker::Grammar);
3524
3525#if ENABLE(DELETION_UI)
3526    m_deleteButtonController->respondToChangedSelection(oldSelection);
3527#endif
3528    if (!m_editorUIUpdateTimerWasTriggeredByDictation)
3529        m_alternativeTextController->respondToChangedSelection(oldSelection);
3530
3531    m_oldSelectionForEditorUIUpdate = m_frame.selection().selection();
3532}
3533
3534static Node* findFirstMarkable(Node* node)
3535{
3536    while (node) {
3537        if (!node->renderer())
3538            return 0;
3539        if (node->renderer()->isTextOrLineBreak())
3540            return node;
3541        if (isHTMLTextFormControlElement(*node))
3542            node = toHTMLTextFormControlElement(node)->visiblePositionForIndex(1).deepEquivalent().deprecatedNode();
3543        else if (node->firstChild())
3544            node = node->firstChild();
3545        else
3546            node = node->nextSibling();
3547    }
3548
3549    return 0;
3550}
3551
3552bool Editor::selectionStartHasMarkerFor(DocumentMarker::MarkerType markerType, int from, int length) const
3553{
3554    Node* node = findFirstMarkable(m_frame.selection().selection().start().deprecatedNode());
3555    if (!node)
3556        return false;
3557
3558    unsigned int startOffset = static_cast<unsigned int>(from);
3559    unsigned int endOffset = static_cast<unsigned int>(from + length);
3560    Vector<DocumentMarker*> markers = document().markers().markersFor(node);
3561    for (size_t i = 0; i < markers.size(); ++i) {
3562        DocumentMarker* marker = markers[i];
3563        if (marker->startOffset() <= startOffset && endOffset <= marker->endOffset() && marker->type() == markerType)
3564            return true;
3565    }
3566
3567    return false;
3568}
3569
3570TextCheckingTypeMask Editor::resolveTextCheckingTypeMask(TextCheckingTypeMask textCheckingOptions)
3571{
3572    bool shouldMarkSpelling = textCheckingOptions & TextCheckingTypeSpelling;
3573    bool shouldMarkGrammar = textCheckingOptions & TextCheckingTypeGrammar;
3574#if !PLATFORM(IOS)
3575    bool shouldShowCorrectionPanel = textCheckingOptions & TextCheckingTypeShowCorrectionPanel;
3576    bool shouldCheckForCorrection = shouldShowCorrectionPanel || (textCheckingOptions & TextCheckingTypeCorrection);
3577#endif
3578
3579    TextCheckingTypeMask checkingTypes = 0;
3580    if (shouldMarkSpelling)
3581        checkingTypes |= TextCheckingTypeSpelling;
3582    if (shouldMarkGrammar)
3583        checkingTypes |= TextCheckingTypeGrammar;
3584#if !PLATFORM(IOS)
3585    if (shouldCheckForCorrection)
3586        checkingTypes |= TextCheckingTypeCorrection;
3587    if (shouldShowCorrectionPanel)
3588        checkingTypes |= TextCheckingTypeShowCorrectionPanel;
3589
3590#if USE(AUTOMATIC_TEXT_REPLACEMENT)
3591    bool shouldPerformReplacement = textCheckingOptions & TextCheckingTypeReplacement;
3592    if (shouldPerformReplacement) {
3593        if (isAutomaticLinkDetectionEnabled())
3594            checkingTypes |= TextCheckingTypeLink;
3595        if (isAutomaticQuoteSubstitutionEnabled())
3596            checkingTypes |= TextCheckingTypeQuote;
3597        if (isAutomaticDashSubstitutionEnabled())
3598            checkingTypes |= TextCheckingTypeDash;
3599        if (isAutomaticTextReplacementEnabled())
3600            checkingTypes |= TextCheckingTypeReplacement;
3601        if (shouldMarkSpelling && isAutomaticSpellingCorrectionEnabled())
3602            checkingTypes |= TextCheckingTypeCorrection;
3603    }
3604#endif
3605#endif // !PLATFORM(IOS)
3606
3607    return checkingTypes;
3608}
3609
3610void Editor::deviceScaleFactorChanged()
3611{
3612#if ENABLE(DELETION_UI)
3613    m_deleteButtonController->deviceScaleFactorChanged();
3614#endif
3615}
3616
3617bool Editor::unifiedTextCheckerEnabled() const
3618{
3619    return WebCore::unifiedTextCheckerEnabled(&m_frame);
3620}
3621
3622Vector<String> Editor::dictationAlternativesForMarker(const DocumentMarker* marker)
3623{
3624    return m_alternativeTextController->dictationAlternativesForMarker(marker);
3625}
3626
3627void Editor::applyDictationAlternativelternative(const String& alternativeString)
3628{
3629    m_alternativeTextController->applyDictationAlternative(alternativeString);
3630}
3631
3632void Editor::toggleOverwriteModeEnabled()
3633{
3634    m_overwriteModeEnabled = !m_overwriteModeEnabled;
3635    m_frame.selection().setShouldShowBlockCursor(m_overwriteModeEnabled);
3636}
3637
3638Document& Editor::document() const
3639{
3640    ASSERT(m_frame.document());
3641    return *m_frame.document();
3642}
3643
3644#if PLATFORM(COCOA)
3645// FIXME: This figures out the current style by inserting a <span>!
3646RenderStyle* Editor::styleForSelectionStart(Frame* frame, Node *&nodeToRemove)
3647{
3648    nodeToRemove = nullptr;
3649
3650    if (frame->selection().isNone())
3651        return nullptr;
3652
3653    Position position = frame->selection().selection().visibleStart().deepEquivalent();
3654    if (!position.isCandidate() || position.isNull())
3655        return nullptr;
3656
3657    RefPtr<EditingStyle> typingStyle = frame->selection().typingStyle();
3658    if (!typingStyle || !typingStyle->style())
3659        return &position.deprecatedNode()->renderer()->style();
3660
3661    RefPtr<Element> styleElement = frame->document()->createElement(spanTag, false);
3662
3663    String styleText = typingStyle->style()->asText() + " display: inline";
3664    styleElement->setAttribute(styleAttr, styleText);
3665
3666    styleElement->appendChild(frame->document()->createEditingTextNode(""), ASSERT_NO_EXCEPTION);
3667
3668    position.deprecatedNode()->parentNode()->appendChild(styleElement, ASSERT_NO_EXCEPTION);
3669
3670    nodeToRemove = styleElement.get();
3671
3672    frame->document()->updateStyleIfNeeded();
3673    return styleElement->renderer() ? &styleElement->renderer()->style() : nullptr;
3674}
3675#endif
3676
3677} // namespace WebCore
3678