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