Rename AtomicString to AtomString
[WebKit-https.git] / Source / WebCore / editing / ReplaceSelectionCommand.cpp
1 /*
2  * Copyright (C) 2005-2017 Apple Inc. All rights reserved.
3  * Copyright (C) 2009, 2010, 2011 Google Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE 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 "ReplaceSelectionCommand.h"
29
30 #include "AXObjectCache.h"
31 #include "ApplyStyleCommand.h"
32 #include "BeforeTextInsertedEvent.h"
33 #include "BreakBlockquoteCommand.h"
34 #include "CSSStyleDeclaration.h"
35 #include "DOMWrapperWorld.h"
36 #include "DataTransfer.h"
37 #include "Document.h"
38 #include "DocumentFragment.h"
39 #include "Editing.h"
40 #include "EditingBehavior.h"
41 #include "ElementIterator.h"
42 #include "EventNames.h"
43 #include "Frame.h"
44 #include "FrameSelection.h"
45 #include "HTMLBRElement.h"
46 #include "HTMLBaseElement.h"
47 #include "HTMLInputElement.h"
48 #include "HTMLLIElement.h"
49 #include "HTMLLinkElement.h"
50 #include "HTMLMetaElement.h"
51 #include "HTMLNames.h"
52 #include "HTMLStyleElement.h"
53 #include "HTMLTitleElement.h"
54 #include "NodeList.h"
55 #include "NodeRenderStyle.h"
56 #include "RenderInline.h"
57 #include "RenderText.h"
58 #include "SimplifyMarkupCommand.h"
59 #include "SmartReplace.h"
60 #include "StyleProperties.h"
61 #include "Text.h"
62 #include "TextIterator.h"
63 #include "VisibleUnits.h"
64 #include "markup.h"
65 #include <wtf/NeverDestroyed.h>
66 #include <wtf/StdLibExtras.h>
67
68 namespace WebCore {
69
70 using namespace HTMLNames;
71
72 enum EFragmentType { EmptyFragment, SingleTextNodeFragment, TreeFragment };
73
74 static void removeHeadContents(ReplacementFragment&);
75
76 // --- ReplacementFragment helper class
77
78 class ReplacementFragment {
79     WTF_MAKE_FAST_ALLOCATED;
80     WTF_MAKE_NONCOPYABLE(ReplacementFragment);
81 public:
82     ReplacementFragment(Document&, DocumentFragment*, const VisibleSelection&);
83
84     DocumentFragment* fragment() { return m_fragment.get(); }
85
86     Node* firstChild() const;
87     Node* lastChild() const;
88
89     bool isEmpty() const;
90     
91     bool hasInterchangeNewlineAtStart() const { return m_hasInterchangeNewlineAtStart; }
92     bool hasInterchangeNewlineAtEnd() const { return m_hasInterchangeNewlineAtEnd; }
93     
94     void removeNode(Node&);
95     void removeNodePreservingChildren(Node&);
96
97 private:
98     Ref<HTMLElement> insertFragmentForTestRendering(Node* rootEditableNode);
99     void removeUnrenderedNodes(Node*);
100     void restoreAndRemoveTestRenderingNodesToFragment(StyledElement*);
101     void removeInterchangeNodes(Node*);
102     
103     void insertNodeBefore(Node&, Node& refNode);
104
105     Document& document() { return *m_document; }
106
107     RefPtr<Document> m_document;
108     RefPtr<DocumentFragment> m_fragment;
109     bool m_hasInterchangeNewlineAtStart;
110     bool m_hasInterchangeNewlineAtEnd;
111 };
112
113 static bool isInterchangeNewlineNode(const Node* node)
114 {
115     static NeverDestroyed<String> interchangeNewlineClassString(AppleInterchangeNewline);
116     return is<HTMLBRElement>(node) && downcast<HTMLBRElement>(*node).attributeWithoutSynchronization(classAttr) == interchangeNewlineClassString;
117 }
118
119 static bool isInterchangeConvertedSpaceSpan(const Node* node)
120 {
121     static NeverDestroyed<String> convertedSpaceSpanClassString(AppleConvertedSpace);
122     return is<HTMLElement>(node) && downcast<HTMLElement>(*node).attributeWithoutSynchronization(classAttr) == convertedSpaceSpanClassString;
123 }
124
125 static Position positionAvoidingPrecedingNodes(Position position)
126 {
127     ASSERT(position.isNotNull());
128
129     // If we're already on a break, it's probably a placeholder and we shouldn't change our position.
130     if (editingIgnoresContent(*position.deprecatedNode()))
131         return position;
132
133     // We also stop when changing block flow elements because even though the visual position is the
134     // same.  E.g.,
135     //   <div>foo^</div>^
136     // The two positions above are the same visual position, but we want to stay in the same block.
137     auto* enclosingBlockNode = enclosingBlock(position.containerNode());
138     for (Position nextPosition = position; nextPosition.containerNode() != enclosingBlockNode; position = nextPosition) {
139         if (lineBreakExistsAtPosition(position))
140             break;
141
142         if (position.containerNode()->nonShadowBoundaryParentNode())
143             nextPosition = positionInParentAfterNode(position.containerNode());
144
145         if (nextPosition == position)
146             break;
147         if (enclosingBlock(nextPosition.containerNode()) != enclosingBlockNode)
148             break;
149         if (VisiblePosition(position) != VisiblePosition(nextPosition))
150             break;
151     }
152     return position;
153 }
154
155 ReplacementFragment::ReplacementFragment(Document& document, DocumentFragment* fragment, const VisibleSelection& selection)
156     : m_document(&document)
157     , m_fragment(fragment)
158     , m_hasInterchangeNewlineAtStart(false)
159     , m_hasInterchangeNewlineAtEnd(false)
160 {
161     if (!m_fragment)
162         return;
163     if (!m_fragment->firstChild())
164         return;
165     
166     RefPtr<Element> editableRoot = selection.rootEditableElement();
167     ASSERT(editableRoot);
168     if (!editableRoot)
169         return;
170     
171     auto* shadowHost = editableRoot->shadowHost();
172     if (!editableRoot->attributeEventListener(eventNames().webkitBeforeTextInsertedEvent, mainThreadNormalWorld())
173         && !(shadowHost && shadowHost->renderer() && shadowHost->renderer()->isTextControl())
174         && editableRoot->hasRichlyEditableStyle()) {
175         removeInterchangeNodes(m_fragment.get());
176         return;
177     }
178
179     RefPtr<StyledElement> holder = insertFragmentForTestRendering(editableRoot.get());
180     if (!holder) {
181         removeInterchangeNodes(m_fragment.get());
182         return;
183     }
184     
185     RefPtr<Range> range = VisibleSelection::selectionFromContentsOfNode(holder.get()).toNormalizedRange();
186     String text = plainText(range.get(), static_cast<TextIteratorBehavior>(TextIteratorEmitsOriginalText | TextIteratorIgnoresStyleVisibility));
187
188     removeInterchangeNodes(holder.get());
189     removeUnrenderedNodes(holder.get());
190     restoreAndRemoveTestRenderingNodesToFragment(holder.get());
191
192     // Give the root a chance to change the text.
193     auto event = BeforeTextInsertedEvent::create(text);
194     editableRoot->dispatchEvent(event);
195     if (text != event->text() || !editableRoot->hasRichlyEditableStyle()) {
196         restoreAndRemoveTestRenderingNodesToFragment(holder.get());
197
198         RefPtr<Range> range = selection.toNormalizedRange();
199         if (!range)
200             return;
201
202         m_fragment = createFragmentFromText(*range, event->text());
203         if (!m_fragment->firstChild())
204             return;
205
206         holder = insertFragmentForTestRendering(editableRoot.get());
207         removeInterchangeNodes(holder.get());
208         removeUnrenderedNodes(holder.get());
209         restoreAndRemoveTestRenderingNodesToFragment(holder.get());
210     }
211 }
212
213 bool ReplacementFragment::isEmpty() const
214 {
215     return (!m_fragment || !m_fragment->firstChild()) && !m_hasInterchangeNewlineAtStart && !m_hasInterchangeNewlineAtEnd;
216 }
217
218 Node *ReplacementFragment::firstChild() const 
219
220     return m_fragment ? m_fragment->firstChild() : 0; 
221 }
222
223 Node *ReplacementFragment::lastChild() const 
224
225     return m_fragment ? m_fragment->lastChild() : 0; 
226 }
227
228 void ReplacementFragment::removeNodePreservingChildren(Node& node)
229 {
230     Ref<Node> protectedNode = node;
231     while (RefPtr<Node> n = node.firstChild()) {
232         removeNode(*n);
233         insertNodeBefore(*n, node);
234     }
235     removeNode(node);
236 }
237
238 void ReplacementFragment::removeNode(Node& node)
239 {
240     ContainerNode* parent = node.nonShadowBoundaryParentNode();
241     if (!parent)
242         return;
243     
244     parent->removeChild(node);
245 }
246
247 void ReplacementFragment::insertNodeBefore(Node& node, Node& refNode)
248 {
249     ContainerNode* parent = refNode.nonShadowBoundaryParentNode();
250     if (!parent)
251         return;
252         
253     parent->insertBefore(node, &refNode);
254 }
255
256 Ref<HTMLElement> ReplacementFragment::insertFragmentForTestRendering(Node* rootEditableElement)
257 {
258     auto holder = createDefaultParagraphElement(document());
259
260     holder->appendChild(*m_fragment);
261     rootEditableElement->appendChild(holder);
262     document().updateLayoutIgnorePendingStylesheets();
263
264     return holder;
265 }
266
267 void ReplacementFragment::restoreAndRemoveTestRenderingNodesToFragment(StyledElement* holder)
268 {
269     if (!holder)
270         return;
271     
272     while (RefPtr<Node> node = holder->firstChild()) {
273         holder->removeChild(*node);
274         m_fragment->appendChild(*node);
275     }
276
277     removeNode(*holder);
278 }
279
280 void ReplacementFragment::removeUnrenderedNodes(Node* holder)
281 {
282     Vector<Ref<Node>> unrendered;
283
284     for (Node* node = holder->firstChild(); node; node = NodeTraversal::next(*node, holder)) {
285         if (!isNodeRendered(*node) && !isTableStructureNode(node))
286             unrendered.append(*node);
287     }
288
289     for (auto& node : unrendered)
290         removeNode(node);
291 }
292
293 void ReplacementFragment::removeInterchangeNodes(Node* container)
294 {
295     m_hasInterchangeNewlineAtStart = false;
296     m_hasInterchangeNewlineAtEnd = false;
297
298     // Interchange newlines at the "start" of the incoming fragment must be
299     // either the first node in the fragment or the first leaf in the fragment.
300     Node* node = container->firstChild();
301     while (node) {
302         if (isInterchangeNewlineNode(node)) {
303             m_hasInterchangeNewlineAtStart = true;
304             removeNode(*node);
305             break;
306         }
307         node = node->firstChild();
308     }
309     if (!container->hasChildNodes())
310         return;
311     // Interchange newlines at the "end" of the incoming fragment must be
312     // either the last node in the fragment or the last leaf in the fragment.
313     node = container->lastChild();
314     while (node) {
315         if (isInterchangeNewlineNode(node)) {
316             m_hasInterchangeNewlineAtEnd = true;
317             removeNode(*node);
318             break;
319         }
320         node = node->lastChild();
321     }
322     
323     node = container->firstChild();
324     while (node) {
325         RefPtr<Node> next = NodeTraversal::next(*node);
326         if (isInterchangeConvertedSpaceSpan(node)) {
327             next = NodeTraversal::nextSkippingChildren(*node);
328             removeNodePreservingChildren(*node);
329         }
330         node = next.get();
331     }
332 }
333
334 inline void ReplaceSelectionCommand::InsertedNodes::respondToNodeInsertion(Node* node)
335 {
336     if (!node)
337         return;
338     
339     if (!m_firstNodeInserted)
340         m_firstNodeInserted = node;
341     
342     m_lastNodeInserted = node;
343 }
344
345 inline void ReplaceSelectionCommand::InsertedNodes::willRemoveNodePreservingChildren(Node* node)
346 {
347     if (m_firstNodeInserted == node)
348         m_firstNodeInserted = NodeTraversal::next(*node);
349     if (m_lastNodeInserted == node) {
350         m_lastNodeInserted = node->lastChild() ? node->lastChild() : NodeTraversal::nextSkippingChildren(*node);
351         if (!m_lastNodeInserted) {
352             // If the last inserted node is at the end of the document and doesn't have any children, look backwards for the
353             // previous node as the last inserted node, clamping to the first inserted node if needed to ensure that the
354             // document position of the last inserted node is not behind the first inserted node.
355             auto* previousNode = NodeTraversal::previousSkippingChildren(*node);
356             ASSERT(previousNode);
357             m_lastNodeInserted = m_firstNodeInserted->compareDocumentPosition(*previousNode) & Node::DOCUMENT_POSITION_FOLLOWING ? previousNode : m_firstNodeInserted;
358         }
359     }
360 }
361
362 inline void ReplaceSelectionCommand::InsertedNodes::willRemoveNode(Node* node)
363 {
364     if (m_firstNodeInserted == node && m_lastNodeInserted == node) {
365         m_firstNodeInserted = nullptr;
366         m_lastNodeInserted = nullptr;
367     } else if (m_firstNodeInserted == node)
368         m_firstNodeInserted = NodeTraversal::nextSkippingChildren(*m_firstNodeInserted);
369     else if (m_lastNodeInserted == node)
370         m_lastNodeInserted = NodeTraversal::previousSkippingChildren(*m_lastNodeInserted);
371 }
372
373 inline void ReplaceSelectionCommand::InsertedNodes::didReplaceNode(Node* node, Node* newNode)
374 {
375     if (m_firstNodeInserted == node)
376         m_firstNodeInserted = newNode;
377     if (m_lastNodeInserted == node)
378         m_lastNodeInserted = newNode;
379 }
380
381 ReplaceSelectionCommand::ReplaceSelectionCommand(Document& document, RefPtr<DocumentFragment>&& fragment, OptionSet<CommandOption> options, EditAction editAction)
382     : CompositeEditCommand(document, editAction)
383     , m_selectReplacement(options & SelectReplacement)
384     , m_smartReplace(options & SmartReplace)
385     , m_matchStyle(options & MatchStyle)
386     , m_documentFragment(fragment)
387     , m_preventNesting(options & PreventNesting)
388     , m_movingParagraph(options & MovingParagraph)
389     , m_sanitizeFragment(options & SanitizeFragment)
390     , m_shouldMergeEnd(false)
391     , m_ignoreMailBlockquote(options & IgnoreMailBlockquote)
392 {
393 }
394
395 static bool hasMatchingQuoteLevel(VisiblePosition endOfExistingContent, VisiblePosition endOfInsertedContent)
396 {
397     Position existing = endOfExistingContent.deepEquivalent();
398     Position inserted = endOfInsertedContent.deepEquivalent();
399     bool isInsideMailBlockquote = enclosingNodeOfType(inserted, isMailBlockquote, CanCrossEditingBoundary);
400     return isInsideMailBlockquote && (numEnclosingMailBlockquotes(existing) == numEnclosingMailBlockquotes(inserted));
401 }
402
403 bool ReplaceSelectionCommand::shouldMergeStart(bool selectionStartWasStartOfParagraph, bool fragmentHasInterchangeNewlineAtStart, bool selectionStartWasInsideMailBlockquote)
404 {
405     if (m_movingParagraph)
406         return false;
407     
408     VisiblePosition startOfInsertedContent(positionAtStartOfInsertedContent());
409     VisiblePosition prev = startOfInsertedContent.previous(CannotCrossEditingBoundary);
410     if (prev.isNull())
411         return false;
412     
413     // When we have matching quote levels, its ok to merge more frequently.
414     // For a successful merge, we still need to make sure that the inserted content starts with the beginning of a paragraph.
415     // And we should only merge here if the selection start was inside a mail blockquote.  This prevents against removing a 
416     // blockquote from newly pasted quoted content that was pasted into an unquoted position.  If that unquoted position happens 
417     // to be right after another blockquote, we don't want to merge and risk stripping a valid block (and newline) from the pasted content.
418     if (isStartOfParagraph(startOfInsertedContent) && selectionStartWasInsideMailBlockquote && hasMatchingQuoteLevel(prev, positionAtEndOfInsertedContent()))
419         return true;
420
421     return !selectionStartWasStartOfParagraph
422         && !fragmentHasInterchangeNewlineAtStart
423         && isStartOfParagraph(startOfInsertedContent)
424         && !startOfInsertedContent.deepEquivalent().deprecatedNode()->hasTagName(brTag)
425         && shouldMerge(startOfInsertedContent, prev);
426 }
427
428 bool ReplaceSelectionCommand::shouldMergeEnd(bool selectionEndWasEndOfParagraph)
429 {
430     VisiblePosition endOfInsertedContent(positionAtEndOfInsertedContent());
431     VisiblePosition next = endOfInsertedContent.next(CannotCrossEditingBoundary);
432     if (next.isNull())
433         return false;
434
435     return !selectionEndWasEndOfParagraph
436         && isEndOfParagraph(endOfInsertedContent)
437         && !endOfInsertedContent.deepEquivalent().deprecatedNode()->hasTagName(brTag)
438         && shouldMerge(endOfInsertedContent, next);
439 }
440
441 static bool isMailPasteAsQuotationNode(const Node* node)
442 {
443     return node && node->hasTagName(blockquoteTag) && downcast<Element>(node)->attributeWithoutSynchronization(classAttr) == ApplePasteAsQuotation;
444 }
445
446 static bool isHeaderElement(const Node* a)
447 {
448     if (!a)
449         return false;
450         
451     return a->hasTagName(h1Tag)
452         || a->hasTagName(h2Tag)
453         || a->hasTagName(h3Tag)
454         || a->hasTagName(h4Tag)
455         || a->hasTagName(h5Tag)
456         || a->hasTagName(h6Tag);
457 }
458
459 static bool haveSameTagName(Node* a, Node* b)
460 {
461     return is<Element>(a) && is<Element>(b) && downcast<Element>(*a).tagName() == downcast<Element>(*b).tagName();
462 }
463
464 bool ReplaceSelectionCommand::shouldMerge(const VisiblePosition& source, const VisiblePosition& destination)
465 {
466     if (source.isNull() || destination.isNull())
467         return false;
468         
469     auto* sourceNode = source.deepEquivalent().deprecatedNode();
470     auto* destinationNode = destination.deepEquivalent().deprecatedNode();
471     auto* sourceBlock = enclosingBlock(sourceNode);
472     auto* destinationBlock = enclosingBlock(destinationNode);
473     return !enclosingNodeOfType(source.deepEquivalent(), &isMailPasteAsQuotationNode)
474         && sourceBlock
475         && (!sourceBlock->hasTagName(blockquoteTag) || isMailBlockquote(sourceBlock))
476         && enclosingListChild(sourceBlock) == enclosingListChild(destinationNode)
477         && enclosingTableCell(source.deepEquivalent()) == enclosingTableCell(destination.deepEquivalent())
478         && (!isHeaderElement(sourceBlock) || haveSameTagName(sourceBlock, destinationBlock))
479         // Don't merge to or from a position before or after a block because it would
480         // be a no-op and cause infinite recursion.
481         && !isBlock(sourceNode) && !isBlock(destinationNode);
482 }
483
484 // Style rules that match just inserted elements could change their appearance, like
485 // a div inserted into a document with div { display:inline; }.
486 void ReplaceSelectionCommand::removeRedundantStylesAndKeepStyleSpanInline(InsertedNodes& insertedNodes)
487 {
488     RefPtr<Node> pastEndNode = insertedNodes.pastLastLeaf();
489     RefPtr<Node> next;
490     for (RefPtr<Node> node = insertedNodes.firstNodeInserted(); node && node != pastEndNode; node = next) {
491         // FIXME: <rdar://problem/5371536> Style rules that match pasted content can change it's appearance
492
493         next = NodeTraversal::next(*node);
494         if (!is<StyledElement>(*node))
495             continue;
496
497         StyledElement* element = downcast<StyledElement>(node.get());
498
499         const StyleProperties* inlineStyle = element->inlineStyle();
500         auto newInlineStyle = EditingStyle::create(inlineStyle);
501         if (inlineStyle) {
502             if (is<HTMLElement>(*element)) {
503                 Vector<QualifiedName> attributes;
504                 HTMLElement& htmlElement = downcast<HTMLElement>(*element);
505
506                 if (newInlineStyle->conflictsWithImplicitStyleOfElement(htmlElement)) {
507                     // e.g. <b style="font-weight: normal;"> is converted to <span style="font-weight: normal;">
508                     node = replaceElementWithSpanPreservingChildrenAndAttributes(htmlElement);
509                     element = downcast<StyledElement>(node.get());
510                     insertedNodes.didReplaceNode(&htmlElement, node.get());
511                 } else if (newInlineStyle->extractConflictingImplicitStyleOfAttributes(htmlElement, EditingStyle::PreserveWritingDirection, nullptr, attributes, EditingStyle::DoNotExtractMatchingStyle)) {
512                     // e.g. <font size="3" style="font-size: 20px;"> is converted to <font style="font-size: 20px;">
513                     for (auto& attribute : attributes)
514                         removeNodeAttribute(*element, attribute);
515                 }
516             }
517
518             ContainerNode* context = element->parentNode();
519
520             // If Mail wraps the fragment with a Paste as Quotation blockquote, or if you're pasting into a quoted region,
521             // styles from blockquoteNode are allowed to override those from the source document, see <rdar://problem/4930986> and <rdar://problem/5089327>.
522             Node* blockquoteNode = isMailPasteAsQuotationNode(context) ? context : enclosingNodeOfType(firstPositionInNode(context), isMailBlockquote, CanCrossEditingBoundary);
523             if (blockquoteNode)
524                 newInlineStyle->removeStyleFromRulesAndContext(*element, document().documentElement());
525
526             newInlineStyle->removeStyleFromRulesAndContext(*element, context);
527         }
528
529         if (!inlineStyle || newInlineStyle->isEmpty()) {
530             if (isStyleSpanOrSpanWithOnlyStyleAttribute(*element) || isEmptyFontTag(element, AllowNonEmptyStyleAttribute)) {
531                 insertedNodes.willRemoveNodePreservingChildren(element);
532                 removeNodePreservingChildren(*element);
533                 continue;
534             }
535             removeNodeAttribute(*element, styleAttr);
536         } else if (newInlineStyle->style()->propertyCount() != inlineStyle->propertyCount())
537             setNodeAttribute(*element, styleAttr, newInlineStyle->style()->asText());
538
539         // FIXME: Tolerate differences in id, class, and style attributes.
540         if (element->parentNode() && isNonTableCellHTMLBlockElement(element) && areIdenticalElements(*element, *element->parentNode())
541             && VisiblePosition(firstPositionInNode(element->parentNode())) == VisiblePosition(firstPositionInNode(element))
542             && VisiblePosition(lastPositionInNode(element->parentNode())) == VisiblePosition(lastPositionInNode(element))) {
543             insertedNodes.willRemoveNodePreservingChildren(element);
544             removeNodePreservingChildren(*element);
545             continue;
546         }
547
548         if (element->parentNode() && element->parentNode()->hasRichlyEditableStyle())
549             removeNodeAttribute(*element, contenteditableAttr);
550
551         // WebKit used to not add display: inline and float: none on copy.
552         // Keep this code around for backward compatibility
553         if (isLegacyAppleStyleSpan(element)) {
554             if (!element->firstChild()) {
555                 insertedNodes.willRemoveNodePreservingChildren(element);
556                 removeNodePreservingChildren(*element);
557                 continue;
558             }
559             // There are other styles that style rules can give to style spans,
560             // but these are the two important ones because they'll prevent
561             // inserted content from appearing in the right paragraph.
562             // FIXME: Hyatt is concerned that selectively using display:inline will give inconsistent
563             // results. We already know one issue because td elements ignore their display property
564             // in quirks mode (which Mail.app is always in). We should look for an alternative.
565
566             // Mutate using the CSSOM wrapper so we get the same event behavior as a script.
567             if (isBlock(element))
568                 element->cssomStyle().setPropertyInternal(CSSPropertyDisplay, "inline", false);
569             if (element->renderer() && element->renderer()->style().isFloating())
570                 element->cssomStyle().setPropertyInternal(CSSPropertyFloat, "none", false);
571         }
572     }
573 }
574
575 static bool isProhibitedParagraphChild(const AtomString& name)
576 {
577     // https://dvcs.w3.org/hg/editing/raw-file/57abe6d3cb60/editing.html#prohibited-paragraph-child
578     static const auto localNames = makeNeverDestroyed([] {
579         static const HTMLQualifiedName* const tags[] = {
580             &addressTag.get(),
581             &articleTag.get(),
582             &asideTag.get(),
583             &blockquoteTag.get(),
584             &captionTag.get(),
585             &centerTag.get(),
586             &colTag.get(),
587             &colgroupTag.get(),
588             &ddTag.get(),
589             &detailsTag.get(),
590             &dirTag.get(),
591             &divTag.get(),
592             &dlTag.get(),
593             &dtTag.get(),
594             &fieldsetTag.get(),
595             &figcaptionTag.get(),
596             &figureTag.get(),
597             &footerTag.get(),
598             &formTag.get(),
599             &h1Tag.get(),
600             &h2Tag.get(),
601             &h3Tag.get(),
602             &h4Tag.get(),
603             &h5Tag.get(),
604             &h6Tag.get(),
605             &headerTag.get(),
606             &hgroupTag.get(),
607             &hrTag.get(),
608             &liTag.get(),
609             &listingTag.get(),
610             &mainTag.get(), // Missing in the specification.
611             &menuTag.get(),
612             &navTag.get(),
613             &olTag.get(),
614             &pTag.get(),
615             &plaintextTag.get(),
616             &preTag.get(),
617             &sectionTag.get(),
618             &summaryTag.get(),
619             &tableTag.get(),
620             &tbodyTag.get(),
621             &tdTag.get(),
622             &tfootTag.get(),
623             &thTag.get(),
624             &theadTag.get(),
625             &trTag.get(),
626             &ulTag.get(),
627             &xmpTag.get(),
628         };
629         HashSet<AtomString> set;
630         for (auto& tag : tags)
631             set.add(tag->localName());
632         return set;
633     }());
634     return localNames.get().contains(name);
635 }
636
637 void ReplaceSelectionCommand::makeInsertedContentRoundTrippableWithHTMLTreeBuilder(InsertedNodes& insertedNodes)
638 {
639     RefPtr<Node> pastEndNode = insertedNodes.pastLastLeaf();
640     RefPtr<Node> next;
641     for (RefPtr<Node> node = insertedNodes.firstNodeInserted(); node && node != pastEndNode; node = next) {
642         next = NodeTraversal::next(*node);
643
644         if (!is<HTMLElement>(*node))
645             continue;
646
647         if (isProhibitedParagraphChild(downcast<HTMLElement>(*node).localName())) {
648             if (auto* paragraphElement = enclosingElementWithTag(positionInParentBeforeNode(node.get()), pTag)) {
649                 auto* parent = paragraphElement->parentNode();
650                 if (parent && parent->hasEditableStyle())
651                     moveNodeOutOfAncestor(*node, *paragraphElement, insertedNodes);
652             }
653         }
654
655         if (isHeaderElement(node.get())) {
656             if (auto* headerElement = highestEnclosingNodeOfType(positionInParentBeforeNode(node.get()), isHeaderElement)) {
657                 if (headerElement->parentNode() && headerElement->parentNode()->isContentRichlyEditable())
658                     moveNodeOutOfAncestor(*node, *headerElement, insertedNodes);
659                 else {
660                     HTMLElement* newSpanElement = replaceElementWithSpanPreservingChildrenAndAttributes(downcast<HTMLElement>(*node));
661                     insertedNodes.didReplaceNode(node.get(), newSpanElement);
662                 }
663             }
664         }
665     }
666 }
667
668 void ReplaceSelectionCommand::moveNodeOutOfAncestor(Node& node, Node& ancestor, InsertedNodes& insertedNodes)
669 {
670     Ref<Node> protectedNode = node;
671     Ref<Node> protectedAncestor = ancestor;
672
673     VisiblePosition positionAtEndOfNode = lastPositionInOrAfterNode(&node);
674     VisiblePosition lastPositionInParagraph = lastPositionInNode(&ancestor);
675     if (positionAtEndOfNode == lastPositionInParagraph) {
676         removeNode(node);
677         if (ancestor.nextSibling())
678             insertNodeBefore(WTFMove(protectedNode), *ancestor.nextSibling());
679         else
680             appendNode(WTFMove(protectedNode), *ancestor.parentNode());
681     } else {
682         RefPtr<Node> nodeToSplitTo = splitTreeToNode(node, ancestor, true);
683         removeNode(node);
684         insertNodeBefore(WTFMove(protectedNode), *nodeToSplitTo);
685     }
686     if (!ancestor.firstChild()) {
687         insertedNodes.willRemoveNode(&ancestor);
688         removeNode(ancestor);
689     }
690 }
691
692 static inline bool hasRenderedText(const Text& text)
693 {
694     return text.renderer() && text.renderer()->hasRenderedText();
695 }
696
697 void ReplaceSelectionCommand::removeUnrenderedTextNodesAtEnds(InsertedNodes& insertedNodes)
698 {
699     document().updateLayoutIgnorePendingStylesheets();
700
701     Node* lastLeafInserted = insertedNodes.lastLeafInserted();
702     if (is<Text>(lastLeafInserted) && !hasRenderedText(downcast<Text>(*lastLeafInserted))
703         && !enclosingElementWithTag(firstPositionInOrBeforeNode(lastLeafInserted), selectTag)
704         && !enclosingElementWithTag(firstPositionInOrBeforeNode(lastLeafInserted), scriptTag)) {
705         insertedNodes.willRemoveNode(lastLeafInserted);
706         removeNode(*lastLeafInserted);
707     }
708
709     // We don't have to make sure that firstNodeInserted isn't inside a select or script element
710     // because it is a top level node in the fragment and the user can't insert into those elements.
711     Node* firstNodeInserted = insertedNodes.firstNodeInserted();
712     if (is<Text>(firstNodeInserted) && !hasRenderedText(downcast<Text>(*firstNodeInserted))) {
713         insertedNodes.willRemoveNode(firstNodeInserted);
714         removeNode(*firstNodeInserted);
715     }
716 }
717
718 VisiblePosition ReplaceSelectionCommand::positionAtEndOfInsertedContent() const
719 {
720     // FIXME: Why is this hack here?  What's special about <select> tags?
721     auto* enclosingSelect = enclosingElementWithTag(m_endOfInsertedContent, selectTag);
722     return enclosingSelect ? lastPositionInOrAfterNode(enclosingSelect) : m_endOfInsertedContent;
723 }
724
725 VisiblePosition ReplaceSelectionCommand::positionAtStartOfInsertedContent() const
726 {
727     return m_startOfInsertedContent;
728 }
729
730 static void removeHeadContents(ReplacementFragment& fragment)
731 {
732     if (fragment.isEmpty())
733         return;
734
735     Vector<Element*> toRemove;
736
737     auto it = descendantsOfType<Element>(*fragment.fragment()).begin();
738     auto end = descendantsOfType<Element>(*fragment.fragment()).end();
739     while (it != end) {
740         if (is<HTMLBaseElement>(*it) || is<HTMLLinkElement>(*it) || is<HTMLMetaElement>(*it) || is<HTMLTitleElement>(*it)
741             || (is<HTMLStyleElement>(*it) && it->getAttribute(classAttr) != WebKitMSOListQuirksStyle)) {
742             toRemove.append(&*it);
743             it.traverseNextSkippingChildren();
744             continue;
745         }
746         ++it;
747     }
748
749     for (auto& element : toRemove)
750         fragment.removeNode(*element);
751 }
752
753 // Remove style spans before insertion if they are unnecessary.  It's faster because we'll 
754 // avoid doing a layout.
755 static bool handleStyleSpansBeforeInsertion(ReplacementFragment& fragment, const Position& insertionPos)
756 {
757     Node* topNode = fragment.firstChild();
758
759     // Handling the case where we are doing Paste as Quotation or pasting into quoted content is more complicated (see handleStyleSpans)
760     // and doesn't receive the optimization.
761     if (isMailPasteAsQuotationNode(topNode) || enclosingNodeOfType(firstPositionInOrBeforeNode(topNode), isMailBlockquote, CanCrossEditingBoundary))
762         return false;
763
764     // Either there are no style spans in the fragment or a WebKit client has added content to the fragment
765     // before inserting it.  Look for and handle style spans after insertion.
766     if (!isLegacyAppleStyleSpan(topNode))
767         return false;
768
769     Node* wrappingStyleSpan = topNode;
770     auto styleAtInsertionPos = EditingStyle::create(insertionPos.parentAnchoredEquivalent());
771     String styleText = styleAtInsertionPos->style()->asText();
772
773     // FIXME: This string comparison is a naive way of comparing two styles.
774     // We should be taking the diff and check that the diff is empty.
775     if (styleText != downcast<Element>(*wrappingStyleSpan).getAttribute(styleAttr))
776         return false;
777
778     fragment.removeNodePreservingChildren(*wrappingStyleSpan);
779     return true;
780 }
781
782 // At copy time, WebKit wraps copied content in a span that contains the source document's 
783 // default styles.  If the copied Range inherits any other styles from its ancestors, we put 
784 // those styles on a second span.
785 // This function removes redundant styles from those spans, and removes the spans if all their 
786 // styles are redundant. 
787 // We should remove the Apple-style-span class when we're done, see <rdar://problem/5685600>.
788 // We should remove styles from spans that are overridden by all of their children, either here
789 // or at copy time.
790 void ReplaceSelectionCommand::handleStyleSpans(InsertedNodes& insertedNodes)
791 {
792     HTMLElement* wrappingStyleSpan = nullptr;
793     // The style span that contains the source document's default style should be at
794     // the top of the fragment, but Mail sometimes adds a wrapper (for Paste As Quotation),
795     // so search for the top level style span instead of assuming it's at the top.
796     for (Node* node = insertedNodes.firstNodeInserted(); node; node = NodeTraversal::next(*node)) {
797         if (isLegacyAppleStyleSpan(node)) {
798             wrappingStyleSpan = downcast<HTMLElement>(node);
799             break;
800         }
801     }
802     
803     // There might not be any style spans if we're pasting from another application or if 
804     // we are here because of a document.execCommand("InsertHTML", ...) call.
805     if (!wrappingStyleSpan)
806         return;
807
808     auto style = EditingStyle::create(wrappingStyleSpan->inlineStyle());
809     ContainerNode* context = wrappingStyleSpan->parentNode();
810
811     // If Mail wraps the fragment with a Paste as Quotation blockquote, or if you're pasting into a quoted region,
812     // styles from blockquoteNode are allowed to override those from the source document, see <rdar://problem/4930986> and <rdar://problem/5089327>.
813     Node* blockquoteNode = isMailPasteAsQuotationNode(context) ? context : enclosingNodeOfType(firstPositionInNode(context), isMailBlockquote, CanCrossEditingBoundary);
814     if (blockquoteNode)
815         context = document().documentElement();
816
817     // This operation requires that only editing styles to be removed from sourceDocumentStyle.
818     style->prepareToApplyAt(firstPositionInNode(context));
819
820     // Remove block properties in the span's style. This prevents properties that probably have no effect 
821     // currently from affecting blocks later if the style is cloned for a new block element during a future 
822     // editing operation.
823     // FIXME: They *can* have an effect currently if blocks beneath the style span aren't individually marked
824     // with block styles by the editing engine used to style them.  WebKit doesn't do this, but others might.
825     style->removeBlockProperties();
826
827     if (style->isEmpty() || !wrappingStyleSpan->firstChild()) {
828         insertedNodes.willRemoveNodePreservingChildren(wrappingStyleSpan);
829         removeNodePreservingChildren(*wrappingStyleSpan);
830     } else
831         setNodeAttribute(*wrappingStyleSpan, styleAttr, style->style()->asText());
832 }
833
834 void ReplaceSelectionCommand::mergeEndIfNeeded()
835 {
836     if (!m_shouldMergeEnd)
837         return;
838
839     VisiblePosition startOfInsertedContent(positionAtStartOfInsertedContent());
840     VisiblePosition endOfInsertedContent(positionAtEndOfInsertedContent());
841     
842     // Bail to avoid infinite recursion.
843     if (m_movingParagraph) {
844         ASSERT_NOT_REACHED();
845         return;
846     }
847     
848     // Merging two paragraphs will destroy the moved one's block styles.  Always move the end of inserted forward 
849     // to preserve the block style of the paragraph already in the document, unless the paragraph to move would 
850     // include the what was the start of the selection that was pasted into, so that we preserve that paragraph's
851     // block styles.
852     bool mergeForward = !(inSameParagraph(startOfInsertedContent, endOfInsertedContent) && !isStartOfParagraph(startOfInsertedContent));
853     
854     VisiblePosition destination = mergeForward ? endOfInsertedContent.next() : endOfInsertedContent;
855     VisiblePosition startOfParagraphToMove = mergeForward ? startOfParagraph(endOfInsertedContent) : endOfInsertedContent.next();
856    
857     // Merging forward could result in deleting the destination anchor node.
858     // To avoid this, we add a placeholder node before the start of the paragraph.
859     if (endOfParagraph(startOfParagraphToMove) == destination) {
860         auto placeholder = HTMLBRElement::create(document());
861         auto* placeholderPtr = placeholder.ptr();
862         insertNodeBefore(WTFMove(placeholder), *startOfParagraphToMove.deepEquivalent().deprecatedNode());
863         destination = VisiblePosition(positionBeforeNode(placeholderPtr));
864     }
865
866     moveParagraph(startOfParagraphToMove, endOfParagraph(startOfParagraphToMove), destination);
867     
868     // Merging forward will remove m_endOfInsertedContent from the document.
869     if (mergeForward) {
870         if (m_startOfInsertedContent.isOrphan())
871             m_startOfInsertedContent = endingSelection().visibleStart().deepEquivalent();
872          m_endOfInsertedContent = endingSelection().visibleEnd().deepEquivalent();
873         // If we merged text nodes, m_endOfInsertedContent could be null. If this is the case, we use m_startOfInsertedContent.
874         if (m_endOfInsertedContent.isNull())
875             m_endOfInsertedContent = m_startOfInsertedContent;
876     }
877 }
878
879 static Node* enclosingInline(Node* node)
880 {
881     while (ContainerNode* parent = node->parentNode()) {
882         if (isBlockFlowElement(*parent) || parent->hasTagName(bodyTag))
883             return node;
884         // Stop if any previous sibling is a block.
885         for (Node* sibling = node->previousSibling(); sibling; sibling = sibling->previousSibling()) {
886             if (isBlockFlowElement(*sibling))
887                 return node;
888         }
889         node = parent;
890     }
891     return node;
892 }
893
894 static bool isInlineNodeWithStyle(const Node* node)
895 {
896     // We don't want to skip over any block elements.
897     if (isBlock(node))
898         return false;
899
900     if (!node->isHTMLElement())
901         return false;
902
903     // We can skip over elements whose class attribute is
904     // one of our internal classes.
905     const HTMLElement* element = static_cast<const HTMLElement*>(node);
906     const AtomString& classAttributeValue = element->attributeWithoutSynchronization(classAttr);
907     if (classAttributeValue == AppleTabSpanClass
908         || classAttributeValue == AppleConvertedSpace
909         || classAttributeValue == ApplePasteAsQuotation)
910         return true;
911
912     return EditingStyle::elementIsStyledSpanOrHTMLEquivalent(*element);
913 }
914
915 inline Node* nodeToSplitToAvoidPastingIntoInlineNodesWithStyle(const Position& insertionPos)
916 {
917     Node* containgBlock = enclosingBlock(insertionPos.containerNode());
918     return highestEnclosingNodeOfType(insertionPos, isInlineNodeWithStyle, CannotCrossEditingBoundary, containgBlock);
919 }
920
921 bool ReplaceSelectionCommand::willApplyCommand()
922 {
923     ensureReplacementFragment();
924     m_documentFragmentPlainText = m_documentFragment->textContent();
925     m_documentFragmentHTMLMarkup = serializeFragment(*m_documentFragment, SerializedNodes::SubtreeIncludingNode);
926     return CompositeEditCommand::willApplyCommand();
927 }
928     
929 static bool hasBlankLineBetweenParagraphs(Position& position)
930 {
931     bool reachedBoundaryStart = false;
932     bool reachedBoundaryEnd = false;
933     VisiblePosition visiblePosition(position);
934     VisiblePosition previousPosition = visiblePosition.previous(CannotCrossEditingBoundary, &reachedBoundaryStart);
935     VisiblePosition nextPosition = visiblePosition.next(CannotCrossEditingBoundary, &reachedBoundaryStart);
936     bool hasLineBeforePosition = isEndOfLine(previousPosition);
937     
938     return !reachedBoundaryStart && !reachedBoundaryEnd && isBlankParagraph(visiblePosition) && hasLineBeforePosition && isStartOfLine(nextPosition);
939 }
940
941 void ReplaceSelectionCommand::doApply()
942 {
943     VisibleSelection selection = endingSelection();
944     ASSERT(selection.isCaretOrRange());
945     ASSERT(selection.start().deprecatedNode());
946     if (selection.isNoneOrOrphaned() || !selection.start().deprecatedNode() || !selection.isContentEditable())
947         return;
948
949     // In plain text only regions, we create style-less fragments, so the inserted content will automatically
950     // match the style of the surrounding area and so we can avoid unnecessary work below for m_matchStyle.
951     if (!selection.isContentRichlyEditable())
952         m_matchStyle = false;
953
954     ReplacementFragment& fragment = *ensureReplacementFragment();
955     if (performTrivialReplace(fragment))
956         return;
957     
958     // We can skip matching the style if the selection is plain text.
959     if ((selection.start().deprecatedNode()->renderer() && selection.start().deprecatedNode()->renderer()->style().userModify() == UserModify::ReadWritePlaintextOnly)
960         && (selection.end().deprecatedNode()->renderer() && selection.end().deprecatedNode()->renderer()->style().userModify() == UserModify::ReadWritePlaintextOnly))
961         m_matchStyle = false;
962     
963     if (m_matchStyle) {
964         m_insertionStyle = EditingStyle::create(selection.start());
965         m_insertionStyle->mergeTypingStyle(document());
966     }
967
968     VisiblePosition visibleStart = selection.visibleStart();
969     VisiblePosition visibleEnd = selection.visibleEnd();
970     
971     bool selectionEndWasEndOfParagraph = isEndOfParagraph(visibleEnd);
972     bool selectionStartWasStartOfParagraph = isStartOfParagraph(visibleStart);
973     
974     Node* startBlock = enclosingBlock(visibleStart.deepEquivalent().deprecatedNode());
975     
976     Position insertionPos = selection.start();
977     bool shouldHandleMailBlockquote = enclosingNodeOfType(insertionPos, isMailBlockquote, CanCrossEditingBoundary) && !m_ignoreMailBlockquote;
978     bool selectionIsPlainText = !selection.isContentRichlyEditable();
979     Element* currentRoot = selection.rootEditableElement();
980
981     if ((selectionStartWasStartOfParagraph && selectionEndWasEndOfParagraph && !shouldHandleMailBlockquote)
982         || startBlock == currentRoot || isListItem(startBlock) || selectionIsPlainText)
983         m_preventNesting = false;
984     
985     if (selection.isRange()) {
986         // When the end of the selection being pasted into is at the end of a paragraph, and that selection
987         // spans multiple blocks, not merging may leave an empty line.
988         // When the start of the selection being pasted into is at the start of a block, not merging 
989         // will leave hanging block(s).
990         // Merge blocks if the start of the selection was in a Mail blockquote, since we handle  
991         // that case specially to prevent nesting. 
992         bool mergeBlocksAfterDelete = shouldHandleMailBlockquote || isEndOfParagraph(visibleEnd) || isStartOfBlock(visibleStart);
993         // FIXME: We should only expand to include fully selected special elements if we are copying a 
994         // selection and pasting it on top of itself.
995         // FIXME: capturing the content of this delete would allow a replace accessibility notification instead of a simple insert
996         deleteSelection(false, mergeBlocksAfterDelete, true, false, true);
997         visibleStart = endingSelection().visibleStart();
998         if (fragment.hasInterchangeNewlineAtStart()) {
999             if (isEndOfParagraph(visibleStart) && !isStartOfParagraph(visibleStart)) {
1000                 if (!isEndOfEditableOrNonEditableContent(visibleStart))
1001                     setEndingSelection(visibleStart.next());
1002             } else
1003                 insertParagraphSeparator();
1004         }
1005         insertionPos = endingSelection().start();
1006     } else {
1007         ASSERT(selection.isCaret());
1008         if (fragment.hasInterchangeNewlineAtStart()) {
1009             VisiblePosition next = visibleStart.next(CannotCrossEditingBoundary);
1010             if (isEndOfParagraph(visibleStart) && !isStartOfParagraph(visibleStart) && next.isNotNull())
1011                 setEndingSelection(next);
1012             else  {
1013                 insertParagraphSeparator();
1014                 visibleStart = endingSelection().visibleStart();
1015             }
1016         }
1017         // We split the current paragraph in two to avoid nesting the blocks from the fragment inside the current block.
1018         // For example paste <div>foo</div><div>bar</div><div>baz</div> into <div>x^x</div>, where ^ is the caret.  
1019         // As long as the  div styles are the same, visually you'd expect: <div>xbar</div><div>bar</div><div>bazx</div>, 
1020         // not <div>xbar<div>bar</div><div>bazx</div></div>.
1021         // Don't do this if the selection started in a Mail blockquote.
1022         if (m_preventNesting && !shouldHandleMailBlockquote && !isEndOfParagraph(visibleStart) && !isStartOfParagraph(visibleStart)) {
1023             insertParagraphSeparator();
1024             setEndingSelection(endingSelection().visibleStart().previous());
1025         }
1026         insertionPos = endingSelection().start();
1027     }
1028     
1029     // We don't want any of the pasted content to end up nested in a Mail blockquote, so first break 
1030     // out of any surrounding Mail blockquotes. Unless we're inserting in a table, in which case
1031     // breaking the blockquote will prevent the content from actually being inserted in the table.
1032     if (shouldHandleMailBlockquote && m_preventNesting && !(enclosingNodeOfType(insertionPos, &isTableStructureNode))) {
1033         applyCommandToComposite(BreakBlockquoteCommand::create(document())); 
1034         // This will leave a br between the split. 
1035         Node* br = endingSelection().start().deprecatedNode(); 
1036         ASSERT(br->hasTagName(brTag)); 
1037         // Insert content between the two blockquotes, but remove the br (since it was just a placeholder). 
1038         insertionPos = positionInParentBeforeNode(br);
1039         removeNode(*br);
1040     }
1041     
1042     // Inserting content could cause whitespace to collapse, e.g. inserting <div>foo</div> into hello^ world.
1043     prepareWhitespaceAtPositionForSplit(insertionPos);
1044
1045     // If the downstream node has been removed there's no point in continuing.
1046     if (!insertionPos.downstream().deprecatedNode())
1047       return;
1048     
1049     // NOTE: This would be an incorrect usage of downstream() if downstream() were changed to mean the last position after 
1050     // p that maps to the same visible position as p (since in the case where a br is at the end of a block and collapsed 
1051     // away, there are positions after the br which map to the same visible position as [br, 0]).  
1052     RefPtr<Node> endBR = insertionPos.downstream().deprecatedNode()->hasTagName(brTag) ? insertionPos.downstream().deprecatedNode() : nullptr;
1053     VisiblePosition originalVisPosBeforeEndBR;
1054     if (endBR)
1055         originalVisPosBeforeEndBR = VisiblePosition(positionBeforeNode(endBR.get()), DOWNSTREAM).previous();
1056     
1057     RefPtr<Node> insertionBlock = enclosingBlock(insertionPos.deprecatedNode());
1058     
1059     // Adjust insertionPos to prevent nesting.
1060     // If the start was in a Mail blockquote, we will have already handled adjusting insertionPos above.
1061     if (m_preventNesting && insertionBlock && !isTableCell(insertionBlock.get()) && !shouldHandleMailBlockquote) {
1062         ASSERT(insertionBlock != currentRoot);
1063         VisiblePosition visibleInsertionPos(insertionPos);
1064         if (isEndOfBlock(visibleInsertionPos) && !(isStartOfBlock(visibleInsertionPos) && fragment.hasInterchangeNewlineAtEnd()))
1065             insertionPos = positionInParentAfterNode(insertionBlock.get());
1066         else if (isStartOfBlock(visibleInsertionPos))
1067             insertionPos = positionInParentBeforeNode(insertionBlock.get());
1068     }
1069     
1070     // Paste at start or end of link goes outside of link.
1071     insertionPos = positionAvoidingSpecialElementBoundary(insertionPos);
1072     
1073     // FIXME: Can this wait until after the operation has been performed?  There doesn't seem to be
1074     // any work performed after this that queries or uses the typing style.
1075     frame().selection().clearTypingStyle();
1076
1077     // We don't want the destination to end up inside nodes that weren't selected.  To avoid that, we move the
1078     // position forward without changing the visible position so we're still at the same visible location, but
1079     // outside of preceding tags.
1080     insertionPos = positionAvoidingPrecedingNodes(insertionPos);
1081
1082     // Paste into run of tabs splits the tab span.
1083     insertionPos = positionOutsideTabSpan(insertionPos);
1084
1085     bool hasBlankLinesBetweenParagraphs = hasBlankLineBetweenParagraphs(insertionPos);
1086     
1087     bool handledStyleSpans = handleStyleSpansBeforeInsertion(fragment, insertionPos);
1088
1089     // We're finished if there is nothing to add.
1090     if (fragment.isEmpty() || !fragment.firstChild())
1091         return;
1092
1093     // If we are not trying to match the destination style we prefer a position
1094     // that is outside inline elements that provide style.
1095     // This way we can produce a less verbose markup.
1096     // We can skip this optimization for fragments not wrapped in one of
1097     // our style spans and for positions inside list items
1098     // since insertAsListItems already does the right thing.
1099     if (!m_matchStyle && !enclosingList(insertionPos.containerNode())) {
1100         if (insertionPos.containerNode()->isTextNode() && insertionPos.offsetInContainerNode() && !insertionPos.atLastEditingPositionForNode()) {
1101             splitTextNode(*insertionPos.containerText(), insertionPos.offsetInContainerNode());
1102             insertionPos = firstPositionInNode(insertionPos.containerNode());
1103         }
1104
1105         if (RefPtr<Node> nodeToSplitTo = nodeToSplitToAvoidPastingIntoInlineNodesWithStyle(insertionPos)) {
1106             if (insertionPos.containerNode() != nodeToSplitTo->parentNode()) {
1107                 Node* splitStart = insertionPos.computeNodeAfterPosition();
1108                 if (!splitStart)
1109                     splitStart = insertionPos.containerNode();
1110                 ASSERT(splitStart);
1111                 nodeToSplitTo = splitTreeToNode(*splitStart, *nodeToSplitTo->parentNode()).get();
1112                 insertionPos = positionInParentBeforeNode(nodeToSplitTo.get());
1113             }
1114         }
1115     }
1116
1117     // FIXME: When pasting rich content we're often prevented from heading down the fast path by style spans.  Try
1118     // again here if they've been removed.
1119
1120     // 1) Insert the content.
1121     // 2) Remove redundant styles and style tags, this inner <b> for example: <b>foo <b>bar</b> baz</b>.
1122     // 3) Merge the start of the added content with the content before the position being pasted into.
1123     // 4) Do one of the following: a) expand the last br if the fragment ends with one and it collapsed,
1124     // b) merge the last paragraph of the incoming fragment with the paragraph that contained the 
1125     // end of the selection that was pasted into, or c) handle an interchange newline at the end of the 
1126     // incoming fragment.
1127     // 5) Add spaces for smart replace.
1128     // 6) Select the replacement if requested, and match style if requested.
1129
1130     InsertedNodes insertedNodes;
1131     RefPtr<Node> refNode = fragment.firstChild();
1132     RefPtr<Node> node = refNode->nextSibling();
1133     
1134     if (refNode)
1135         fragment.removeNode(*refNode);
1136
1137     Node* blockStart = enclosingBlock(insertionPos.deprecatedNode());
1138     bool isInsertingIntoList = (isListHTMLElement(refNode.get()) || (isLegacyAppleStyleSpan(refNode.get()) && isListHTMLElement(refNode->firstChild())))
1139     && blockStart && blockStart->renderer()->isListItem();
1140     if (isInsertingIntoList)
1141         refNode = insertAsListItems(downcast<HTMLElement>(*refNode), blockStart, insertionPos, insertedNodes);
1142     else {
1143         insertNodeAt(*refNode, insertionPos);
1144         insertedNodes.respondToNodeInsertion(refNode.get());
1145     }
1146
1147     // Mutation events (bug 22634) may have already removed the inserted content
1148     if (!refNode->isConnected())
1149         return;
1150
1151     bool plainTextFragment = isPlainTextMarkup(refNode.get());
1152
1153     while (node) {
1154         RefPtr<Node> next = node->nextSibling();
1155         fragment.removeNode(*node);
1156         insertNodeAfter(*node, *refNode);
1157         insertedNodes.respondToNodeInsertion(node.get());
1158
1159         // Mutation events (bug 22634) may have already removed the inserted content
1160         if (!node->isConnected())
1161             return;
1162
1163         refNode = node;
1164         if (node && plainTextFragment)
1165             plainTextFragment = isPlainTextMarkup(node.get());
1166         node = next;
1167     }
1168
1169     if (insertedNodes.isEmpty())
1170         return;
1171     removeUnrenderedTextNodesAtEnds(insertedNodes);
1172
1173     if (!handledStyleSpans)
1174         handleStyleSpans(insertedNodes);
1175
1176     // Mutation events (bug 20161) may have already removed the inserted content
1177     if (insertedNodes.isEmpty())
1178         return;
1179     if (!insertedNodes.firstNodeInserted()->isConnected())
1180         return;
1181
1182     VisiblePosition startOfInsertedContent = firstPositionInOrBeforeNode(insertedNodes.firstNodeInserted());
1183
1184     // We inserted before the insertionBlock to prevent nesting, and the content before the insertionBlock wasn't in its own block and
1185     // didn't have a br after it, so the inserted content ended up in the same paragraph.
1186     if (!startOfInsertedContent.isNull() && insertionBlock && insertionPos.deprecatedNode() == insertionBlock->parentNode() && (unsigned)insertionPos.deprecatedEditingOffset() < insertionBlock->computeNodeIndex() && !isStartOfParagraph(startOfInsertedContent))
1187         insertNodeAt(HTMLBRElement::create(document()), startOfInsertedContent.deepEquivalent());
1188
1189     if (endBR && (plainTextFragment || shouldRemoveEndBR(endBR.get(), originalVisPosBeforeEndBR))) {
1190         RefPtr<Node> parent = endBR->parentNode();
1191         insertedNodes.willRemoveNode(endBR.get());
1192         removeNode(*endBR);
1193         if (Node* nodeToRemove = highestNodeToRemoveInPruning(parent.get())) {
1194             insertedNodes.willRemoveNode(nodeToRemove);
1195             removeNode(*nodeToRemove);
1196         }
1197     }
1198     
1199     makeInsertedContentRoundTrippableWithHTMLTreeBuilder(insertedNodes);
1200     if (insertedNodes.isEmpty())
1201         return;
1202
1203     removeRedundantStylesAndKeepStyleSpanInline(insertedNodes);
1204     if (insertedNodes.isEmpty())
1205         return;
1206
1207     if (m_sanitizeFragment)
1208         applyCommandToComposite(SimplifyMarkupCommand::create(document(), insertedNodes.firstNodeInserted(), insertedNodes.pastLastLeaf()));
1209
1210     // Setup m_startOfInsertedContent and m_endOfInsertedContent. This should be the last two lines of code that access insertedNodes.
1211     m_startOfInsertedContent = firstPositionInOrBeforeNode(insertedNodes.firstNodeInserted());
1212     m_endOfInsertedContent = lastPositionInOrAfterNode(insertedNodes.lastLeafInserted());
1213
1214     // Determine whether or not we should merge the end of inserted content with what's after it before we do
1215     // the start merge so that the start merge doesn't effect our decision.
1216     m_shouldMergeEnd = shouldMergeEnd(selectionEndWasEndOfParagraph);
1217     
1218     if (shouldMergeStart(selectionStartWasStartOfParagraph, fragment.hasInterchangeNewlineAtStart(), shouldHandleMailBlockquote)) {
1219         VisiblePosition startOfParagraphToMove = positionAtStartOfInsertedContent();
1220         VisiblePosition destination = startOfParagraphToMove.previous();
1221         // We need to handle the case where we need to merge the end
1222         // but our destination node is inside an inline that is the last in the block.
1223         // We insert a placeholder before the newly inserted content to avoid being merged into the inline.
1224         Node* destinationNode = destination.deepEquivalent().deprecatedNode();
1225         if (m_shouldMergeEnd && destinationNode != enclosingInline(destinationNode) && enclosingInline(destinationNode)->nextSibling())
1226             insertNodeBefore(HTMLBRElement::create(document()), *refNode);
1227         
1228         // Merging the first paragraph of inserted content with the content that came
1229         // before the selection that was pasted into would also move content after 
1230         // the selection that was pasted into if: only one paragraph was being pasted, 
1231         // and it was not wrapped in a block, the selection that was pasted into ended 
1232         // at the end of a block and the next paragraph didn't start at the start of a block.
1233         // Insert a line break just after the inserted content to separate it from what 
1234         // comes after and prevent that from happening.
1235         VisiblePosition endOfInsertedContent = positionAtEndOfInsertedContent();
1236         if (startOfParagraph(endOfInsertedContent) == startOfParagraphToMove) {
1237             insertNodeAt(HTMLBRElement::create(document()), endOfInsertedContent.deepEquivalent());
1238             // Mutation events (bug 22634) triggered by inserting the <br> might have removed the content we're about to move
1239             if (!startOfParagraphToMove.deepEquivalent().anchorNode()->isConnected())
1240                 return;
1241         }
1242
1243         // FIXME: Maintain positions for the start and end of inserted content instead of keeping nodes.  The nodes are
1244         // only ever used to create positions where inserted content starts/ends.
1245         moveParagraph(startOfParagraphToMove, endOfParagraph(startOfParagraphToMove), destination);
1246         m_startOfInsertedContent = endingSelection().visibleStart().deepEquivalent().downstream();
1247         if (m_endOfInsertedContent.isOrphan())
1248             m_endOfInsertedContent = endingSelection().visibleEnd().deepEquivalent().upstream();
1249     }
1250
1251     Position lastPositionToSelect;
1252     if (fragment.hasInterchangeNewlineAtEnd()) {
1253         VisiblePosition endOfInsertedContent = positionAtEndOfInsertedContent();
1254         VisiblePosition next = endOfInsertedContent.next(CannotCrossEditingBoundary);
1255
1256         if (selectionEndWasEndOfParagraph || !isEndOfParagraph(endOfInsertedContent) || next.isNull()) {
1257             if (!isStartOfParagraph(endOfInsertedContent)) {
1258                 setEndingSelection(endOfInsertedContent);
1259                 Node* enclosingNode = enclosingBlock(endOfInsertedContent.deepEquivalent().deprecatedNode());
1260                 if (isListItem(enclosingNode)) {
1261                     auto newListItem = HTMLLIElement::create(document());
1262                     insertNodeAfter(newListItem.copyRef(), *enclosingNode);
1263                     setEndingSelection(VisiblePosition(firstPositionInNode(newListItem.ptr())));
1264                 } else {
1265                     // Use a default paragraph element (a plain div) for the empty paragraph, using the last paragraph
1266                     // block's style seems to annoy users.
1267                     insertParagraphSeparator(true, !shouldHandleMailBlockquote && highestEnclosingNodeOfType(endOfInsertedContent.deepEquivalent(),
1268                         isMailBlockquote, CannotCrossEditingBoundary, insertedNodes.firstNodeInserted()->parentNode()));
1269                 }
1270
1271                 // Select up to the paragraph separator that was added.
1272                 lastPositionToSelect = endingSelection().visibleStart().deepEquivalent();
1273                 updateNodesInserted(lastPositionToSelect.deprecatedNode());
1274             }
1275         } else {
1276             // Select up to the beginning of the next paragraph.
1277             lastPositionToSelect = next.deepEquivalent().downstream();
1278         }
1279         
1280     } else
1281         mergeEndIfNeeded();
1282
1283     if (Node* mailBlockquote = enclosingNodeOfType(positionAtStartOfInsertedContent().deepEquivalent(), isMailPasteAsQuotationNode))
1284         removeNodeAttribute(downcast<Element>(*mailBlockquote), classAttr);
1285
1286     if (shouldPerformSmartReplace())
1287         addSpacesForSmartReplace();
1288
1289     if (!isInsertingIntoList && hasBlankLinesBetweenParagraphs && shouldPerformSmartParagraphReplace())
1290         addNewLinesForSmartReplace();
1291
1292     // If we are dealing with a fragment created from plain text
1293     // no style matching is necessary.
1294     if (plainTextFragment)
1295         m_matchStyle = false;
1296         
1297     completeHTMLReplacement(lastPositionToSelect);
1298 }
1299
1300 String ReplaceSelectionCommand::inputEventData() const
1301 {
1302     if (isEditingTextAreaOrTextInput())
1303         return m_documentFragment->textContent();
1304
1305     return CompositeEditCommand::inputEventData();
1306 }
1307
1308 RefPtr<DataTransfer> ReplaceSelectionCommand::inputEventDataTransfer() const
1309 {
1310     if (isEditingTextAreaOrTextInput())
1311         return CompositeEditCommand::inputEventDataTransfer();
1312
1313     return DataTransfer::createForInputEvent(m_documentFragmentPlainText, m_documentFragmentHTMLMarkup);
1314 }
1315
1316 bool ReplaceSelectionCommand::shouldRemoveEndBR(Node* endBR, const VisiblePosition& originalVisPosBeforeEndBR)
1317 {
1318     if (!endBR || !endBR->isConnected())
1319         return false;
1320
1321     VisiblePosition visiblePos(positionBeforeNode(endBR));
1322     
1323     // Don't remove the br if nothing was inserted.
1324     if (visiblePos.previous() == originalVisPosBeforeEndBR)
1325         return false;
1326     
1327     // Remove the br if it is collapsed away and so is unnecessary.
1328     if (!document().inNoQuirksMode() && isEndOfBlock(visiblePos) && !isStartOfParagraph(visiblePos))
1329         return true;
1330         
1331     // A br that was originally holding a line open should be displaced by inserted content or turned into a line break.
1332     // A br that was originally acting as a line break should still be acting as a line break, not as a placeholder.
1333     return isStartOfParagraph(visiblePos) && isEndOfParagraph(visiblePos);
1334 }
1335
1336 bool ReplaceSelectionCommand::shouldPerformSmartReplace() const
1337 {
1338     if (!m_smartReplace)
1339         return false;
1340
1341     Element* textControl = enclosingTextFormControl(positionAtStartOfInsertedContent().deepEquivalent());
1342     if (is<HTMLInputElement>(textControl) && downcast<HTMLInputElement>(*textControl).isPasswordField())
1343         return false; // Disable smart replace for password fields.
1344
1345     return true;
1346 }
1347     
1348 bool ReplaceSelectionCommand::shouldPerformSmartParagraphReplace() const
1349 {
1350     if (!m_smartReplace)
1351         return false;
1352
1353     if (!document().editingBehavior().shouldSmartInsertDeleteParagraphs())
1354         return false;
1355
1356     return true;
1357 }
1358
1359 static bool isCharacterSmartReplaceExemptConsideringNonBreakingSpace(UChar32 character, bool previousCharacter)
1360 {
1361     return isCharacterSmartReplaceExempt(character == noBreakSpace ? ' ' : character, previousCharacter);
1362 }
1363
1364 void ReplaceSelectionCommand::addNewLinesForSmartReplace()
1365 {
1366     VisiblePosition startOfInsertedContent = positionAtStartOfInsertedContent();
1367     VisiblePosition endOfInsertedContent = positionAtEndOfInsertedContent();
1368
1369     bool isPastedContentEntireParagraphs = isStartOfParagraph(startOfInsertedContent) && isEndOfParagraph(endOfInsertedContent);
1370
1371     // If we aren't pasting a paragraph, no need to attempt to insert newlines.
1372     if (!isPastedContentEntireParagraphs)
1373         return;
1374
1375     bool reachedBoundaryStart = false;
1376     bool reachedBoundaryEnd = false;
1377     VisiblePosition positionBeforeStart = startOfInsertedContent.previous(CannotCrossEditingBoundary, &reachedBoundaryStart);
1378     VisiblePosition positionAfterEnd = endOfInsertedContent.next(CannotCrossEditingBoundary, &reachedBoundaryEnd);
1379
1380     if (!reachedBoundaryStart && !reachedBoundaryEnd) {
1381         if (!isBlankParagraph(positionBeforeStart) && !isBlankParagraph(startOfInsertedContent) && isEndOfLine(positionBeforeStart) && !isEndOfEditableOrNonEditableContent(positionAfterEnd) && !isEndOfEditableOrNonEditableContent(endOfInsertedContent)) {
1382             setEndingSelection(startOfInsertedContent);
1383             insertParagraphSeparator();
1384             auto newStart = endingSelection().visibleStart().previous(CannotCrossEditingBoundary, &reachedBoundaryStart);
1385             if (!reachedBoundaryStart)
1386                 m_startOfInsertedContent = newStart.deepEquivalent();
1387         }
1388     }
1389
1390     reachedBoundaryStart = false;
1391     reachedBoundaryEnd = false;
1392     positionAfterEnd = endOfInsertedContent.next(CannotCrossEditingBoundary, &reachedBoundaryEnd);
1393     positionBeforeStart = startOfInsertedContent.previous(CannotCrossEditingBoundary, &reachedBoundaryStart);
1394
1395     if (!reachedBoundaryEnd && !reachedBoundaryStart) {
1396         if (!isBlankParagraph(positionAfterEnd) && !isBlankParagraph(endOfInsertedContent) && isStartOfLine(positionAfterEnd) && !isEndOfLine(positionAfterEnd) && !isEndOfEditableOrNonEditableContent(positionAfterEnd)) {
1397             setEndingSelection(endOfInsertedContent);
1398             insertParagraphSeparator();
1399             m_endOfInsertedContent = endingSelection().start();
1400         }
1401     }
1402 }
1403
1404 void ReplaceSelectionCommand::addSpacesForSmartReplace()
1405 {
1406     VisiblePosition startOfInsertedContent = positionAtStartOfInsertedContent();
1407     VisiblePosition endOfInsertedContent = positionAtEndOfInsertedContent();
1408
1409     Position endUpstream = endOfInsertedContent.deepEquivalent().upstream();
1410     Node* endNode = endUpstream.computeNodeBeforePosition();
1411     int endOffset = is<Text>(endNode) ? downcast<Text>(*endNode).length() : 0;
1412     if (endUpstream.anchorType() == Position::PositionIsOffsetInAnchor) {
1413         endNode = endUpstream.containerNode();
1414         endOffset = endUpstream.offsetInContainerNode();
1415     }
1416
1417     bool needsTrailingSpace = !isEndOfParagraph(endOfInsertedContent) && !isStartOfParagraph(endOfInsertedContent) && !isCharacterSmartReplaceExemptConsideringNonBreakingSpace(endOfInsertedContent.characterAfter(), false);
1418     if (needsTrailingSpace && endNode) {
1419         bool collapseWhiteSpace = !endNode->renderer() || endNode->renderer()->style().collapseWhiteSpace();
1420         if (is<Text>(*endNode)) {
1421             insertTextIntoNode(downcast<Text>(*endNode), endOffset, collapseWhiteSpace ? nonBreakingSpaceString() : " ");
1422             if (m_endOfInsertedContent.containerNode() == endNode)
1423                 m_endOfInsertedContent.moveToOffset(m_endOfInsertedContent.offsetInContainerNode() + 1);
1424         } else {
1425             auto node = document().createEditingTextNode(collapseWhiteSpace ? nonBreakingSpaceString() : " ");
1426             insertNodeAfter(node.copyRef(), *endNode);
1427             updateNodesInserted(node.ptr());
1428         }
1429     }
1430
1431     document().updateLayout();
1432
1433     Position startDownstream = startOfInsertedContent.deepEquivalent().downstream();
1434     Node* startNode = startDownstream.computeNodeAfterPosition();
1435     unsigned startOffset = 0;
1436     if (startDownstream.anchorType() == Position::PositionIsOffsetInAnchor) {
1437         startNode = startDownstream.containerNode();
1438         startOffset = startDownstream.offsetInContainerNode();
1439     }
1440
1441     bool needsLeadingSpace = !isStartOfParagraph(startOfInsertedContent) && !isEndOfParagraph(startOfInsertedContent) && !isCharacterSmartReplaceExemptConsideringNonBreakingSpace(startOfInsertedContent.previous().characterAfter(), true);
1442     if (needsLeadingSpace && startNode) {
1443         bool collapseWhiteSpace = !startNode->renderer() || startNode->renderer()->style().collapseWhiteSpace();
1444         if (is<Text>(*startNode)) {
1445             insertTextIntoNode(downcast<Text>(*startNode), startOffset, collapseWhiteSpace ? nonBreakingSpaceString() : " ");
1446             if (m_endOfInsertedContent.containerNode() == startNode && m_endOfInsertedContent.offsetInContainerNode())
1447                 m_endOfInsertedContent.moveToOffset(m_endOfInsertedContent.offsetInContainerNode() + 1);
1448         } else {
1449             auto node = document().createEditingTextNode(collapseWhiteSpace ? nonBreakingSpaceString() : " ");
1450             auto* nodePtr = node.ptr();
1451             // Don't updateNodesInserted. Doing so would set m_endOfInsertedContent to be the node containing the leading space,
1452             // but m_endOfInsertedContent is supposed to mark the end of pasted content.
1453             insertNodeBefore(WTFMove(node), *startNode);
1454             m_startOfInsertedContent = firstPositionInNode(nodePtr);
1455         }
1456     }
1457 }
1458
1459 void ReplaceSelectionCommand::completeHTMLReplacement(const Position &lastPositionToSelect)
1460 {
1461     Position start = positionAtStartOfInsertedContent().deepEquivalent();
1462     Position end = positionAtEndOfInsertedContent().deepEquivalent();
1463
1464     // Mutation events may have deleted start or end
1465     if (start.isNotNull() && !start.isOrphan() && end.isNotNull() && !end.isOrphan()) {
1466         // FIXME (11475): Remove this and require that the creator of the fragment to use nbsps.
1467         rebalanceWhitespaceAt(start);
1468         rebalanceWhitespaceAt(end);
1469
1470         if (m_matchStyle) {
1471             ASSERT(m_insertionStyle);
1472             applyStyle(m_insertionStyle.get(), start, end);
1473         }
1474
1475         if (lastPositionToSelect.isNotNull())
1476             end = lastPositionToSelect;
1477
1478         mergeTextNodesAroundPosition(start, end);
1479         mergeTextNodesAroundPosition(end, start);
1480     } else if (lastPositionToSelect.isNotNull())
1481         start = end = lastPositionToSelect;
1482     else
1483         return;
1484
1485     if (AXObjectCache::accessibilityEnabled() && editingAction() == EditAction::Paste)
1486         m_visibleSelectionForInsertedText = VisibleSelection(start, end);
1487
1488     if (m_selectReplacement)
1489         setEndingSelection(VisibleSelection(start, end, SEL_DEFAULT_AFFINITY, endingSelection().isDirectional()));
1490     else
1491         setEndingSelection(VisibleSelection(end, SEL_DEFAULT_AFFINITY, endingSelection().isDirectional()));
1492 }
1493
1494 void ReplaceSelectionCommand::mergeTextNodesAroundPosition(Position& position, Position& positionOnlyToBeUpdated)
1495 {
1496     bool positionIsOffsetInAnchor = position.anchorType() == Position::PositionIsOffsetInAnchor;
1497     bool positionOnlyToBeUpdatedIsOffsetInAnchor = positionOnlyToBeUpdated.anchorType() == Position::PositionIsOffsetInAnchor;
1498     RefPtr<Text> text;
1499     if (positionIsOffsetInAnchor && is<Text>(position.containerNode()))
1500         text = downcast<Text>(position.containerNode());
1501     else {
1502         Node* before = position.computeNodeBeforePosition();
1503         if (is<Text>(before))
1504             text = downcast<Text>(before);
1505         else {
1506             Node* after = position.computeNodeAfterPosition();
1507             if (is<Text>(after))
1508                 text = downcast<Text>(after);
1509         }
1510     }
1511     if (!text)
1512         return;
1513
1514     if (is<Text>(text->previousSibling())) {
1515         Ref<Text> previous(downcast<Text>(*text->previousSibling()));
1516         insertTextIntoNode(*text, 0, previous->data());
1517
1518         if (positionIsOffsetInAnchor)
1519             position.moveToOffset(previous->length() + position.offsetInContainerNode());
1520         else
1521             updatePositionForNodeRemoval(position, previous.get());
1522
1523         if (positionOnlyToBeUpdatedIsOffsetInAnchor) {
1524             if (positionOnlyToBeUpdated.containerNode() == text)
1525                 positionOnlyToBeUpdated.moveToOffset(previous->length() + positionOnlyToBeUpdated.offsetInContainerNode());
1526             else if (positionOnlyToBeUpdated.containerNode() == previous.ptr())
1527                 positionOnlyToBeUpdated.moveToPosition(text.get(), positionOnlyToBeUpdated.offsetInContainerNode());
1528         } else
1529             updatePositionForNodeRemoval(positionOnlyToBeUpdated, previous.get());
1530
1531         removeNode(previous);
1532     }
1533     if (is<Text>(text->nextSibling())) {
1534         Ref<Text> next(downcast<Text>(*text->nextSibling()));
1535         unsigned originalLength = text->length();
1536         insertTextIntoNode(*text, originalLength, next->data());
1537
1538         if (!positionIsOffsetInAnchor)
1539             updatePositionForNodeRemoval(position, next.get());
1540
1541         if (positionOnlyToBeUpdatedIsOffsetInAnchor && positionOnlyToBeUpdated.containerNode() == next.ptr())
1542             positionOnlyToBeUpdated.moveToPosition(text.get(), originalLength + positionOnlyToBeUpdated.offsetInContainerNode());
1543         else
1544             updatePositionForNodeRemoval(positionOnlyToBeUpdated, next.get());
1545
1546         removeNode(next);
1547     }
1548 }
1549
1550 static HTMLElement* singleChildList(HTMLElement& element)
1551 {
1552     if (!element.hasOneChild())
1553         return nullptr;
1554
1555     auto& child = *element.firstChild();
1556     return isListHTMLElement(&child) ? &downcast<HTMLElement>(child) : nullptr;
1557 }
1558
1559 static HTMLElement& deepestSingleChildList(HTMLElement& topLevelList)
1560 {
1561     auto* list = &topLevelList;
1562     while (auto* childList = singleChildList(*list))
1563         list = childList;
1564     return *list;
1565 }
1566
1567 // If the user is inserting a list into an existing list, instead of nesting the list,
1568 // we put the list items into the existing list.
1569 Node* ReplaceSelectionCommand::insertAsListItems(HTMLElement& passedListElement, Node* insertionBlock, const Position& insertPos, InsertedNodes& insertedNodes)
1570 {
1571     Ref<HTMLElement> listElement = deepestSingleChildList(passedListElement);
1572
1573     bool isStart = isStartOfParagraph(insertPos);
1574     bool isEnd = isEndOfParagraph(insertPos);
1575     bool isMiddle = !isStart && !isEnd;
1576     Node* lastNode = insertionBlock;
1577
1578     // If we're in the middle of a list item, we should split it into two separate
1579     // list items and insert these nodes between them.
1580     if (isMiddle) {
1581         int textNodeOffset = insertPos.offsetInContainerNode();
1582         if (is<Text>(*insertPos.deprecatedNode()) && textNodeOffset > 0)
1583             splitTextNode(downcast<Text>(*insertPos.deprecatedNode()), textNodeOffset);
1584         splitTreeToNode(*insertPos.deprecatedNode(), *lastNode, true);
1585     }
1586
1587     while (RefPtr<Node> listItem = listElement->firstChild()) {
1588         listElement->removeChild(*listItem);
1589         if (isStart || isMiddle) {
1590             insertNodeBefore(*listItem, *lastNode);
1591             insertedNodes.respondToNodeInsertion(listItem.get());
1592         } else if (isEnd) {
1593             insertNodeAfter(*listItem, *lastNode);
1594             insertedNodes.respondToNodeInsertion(listItem.get());
1595             lastNode = listItem.get();
1596         } else
1597             ASSERT_NOT_REACHED();
1598     }
1599     if ((isStart || isMiddle) && lastNode->previousSibling())
1600         lastNode = lastNode->previousSibling();
1601     return lastNode;
1602 }
1603
1604 void ReplaceSelectionCommand::updateNodesInserted(Node *node)
1605 {
1606     if (!node)
1607         return;
1608
1609     if (m_startOfInsertedContent.isNull())
1610         m_startOfInsertedContent = firstPositionInOrBeforeNode(node);
1611
1612     m_endOfInsertedContent = lastPositionInOrAfterNode(node->lastDescendant());
1613 }
1614
1615 ReplacementFragment* ReplaceSelectionCommand::ensureReplacementFragment()
1616 {
1617     if (!m_replacementFragment) {
1618         m_replacementFragment = std::make_unique<ReplacementFragment>(document(), m_documentFragment.get(), endingSelection());
1619         removeHeadContents(*m_replacementFragment);
1620     }
1621
1622     return m_replacementFragment.get();
1623 }
1624
1625 // During simple pastes, where we're just pasting a text node into a run of text, we insert the text node
1626 // directly into the text node that holds the selection.  This is much faster than the generalized code in
1627 // ReplaceSelectionCommand, and works around <https://bugs.webkit.org/show_bug.cgi?id=6148> since we don't 
1628 // split text nodes.
1629 bool ReplaceSelectionCommand::performTrivialReplace(const ReplacementFragment& fragment)
1630 {
1631     if (!is<Text>(fragment.firstChild()) || fragment.firstChild() != fragment.lastChild())
1632         return false;
1633
1634     // FIXME: Would be nice to handle smart replace in the fast path.
1635     if (m_smartReplace || fragment.hasInterchangeNewlineAtStart() || fragment.hasInterchangeNewlineAtEnd())
1636         return false;
1637
1638     // e.g. when "bar" is inserted after "foo" in <div><u>foo</u></div>, "bar" should not be underlined.
1639     if (nodeToSplitToAvoidPastingIntoInlineNodesWithStyle(endingSelection().start()))
1640         return false;
1641
1642     RefPtr<Node> nodeAfterInsertionPos = endingSelection().end().downstream().anchorNode();
1643     Text& textNode = downcast<Text>(*fragment.firstChild());
1644     // Our fragment creation code handles tabs, spaces, and newlines, so we don't have to worry about those here.
1645
1646     Position start = endingSelection().start();
1647     Position end = replaceSelectedTextInNode(textNode.data());
1648     if (end.isNull())
1649         return false;
1650
1651     if (nodeAfterInsertionPos && nodeAfterInsertionPos->parentNode() && nodeAfterInsertionPos->hasTagName(brTag)
1652         && shouldRemoveEndBR(nodeAfterInsertionPos.get(), positionBeforeNode(nodeAfterInsertionPos.get())))
1653         removeNodeAndPruneAncestors(*nodeAfterInsertionPos);
1654
1655     VisibleSelection selectionAfterReplace(m_selectReplacement ? start : end, end);
1656
1657     if (AXObjectCache::accessibilityEnabled() && editingAction() == EditAction::Paste)
1658         m_visibleSelectionForInsertedText = VisibleSelection(start, end);
1659
1660     setEndingSelection(selectionAfterReplace);
1661
1662     return true;
1663 }
1664
1665 } // namespace WebCore