<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[246868] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/246868">246868</a></dd>
<dt>Author</dt> <dd>rniwa@webkit.org</dd>
<dt>Date</dt> <dd>2019-06-26 19:55:58 -0700 (Wed, 26 Jun 2019)</dd>
</dl>

<h3>Log Message</h3>
<pre>ReplacementFragment should not have script observable side effects
https://bugs.webkit.org/show_bug.cgi?id=199147

Reviewed by Wenson Hsieh.

Source/WebCore:

Fixed the bug that ReplacementFragment has script observable side effects.

Use a brand new document for sanitization where the script is disabled for test rendering,
and remove style and script elements as well as event handlers before the test rendering
and the actual pasting.

Test: editing/pasteboard/paste-contents-with-side-effects.html

* editing/ReplaceSelectionCommand.cpp:
(WebCore::ReplacementFragment::document): Deleted.
(WebCore::ReplacementFragment::ReplacementFragment): Use createPageForSanitizingWebContent
to create our own document for test rendering. We need to copy over the computed style
from the root editable element (editing host) to respect whitespace treatment, etc...
(WebCore::ReplacementFragment::removeContentsWithSideEffects): Moved from removeHeadContents.
Now removes event handlers and JavaScript URLs.
(WebCore::ReplacementFragment::insertFragmentForTestRendering): Renamed variable names.
(WebCore::ReplaceSelectionCommand::willApplyCommand): Create the plain text and HTML markup
for beforeinput and input events before ReplacementFragment removes contents with side effects.
(WebCore::ReplaceSelectionCommand::ensureReplacementFragment): The removal of head elements
is now done in ReplacementFragment's constructor.

LayoutTests:

Added regression tests.

* editing/pasteboard/paste-contents-with-side-effects-expected.txt: Added.
* editing/pasteboard/paste-contents-with-side-effects.html: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreeditingReplaceSelectionCommandcpp">trunk/Source/WebCore/editing/ReplaceSelectionCommand.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestseditingpasteboardpastecontentswithsideeffectsexpectedtxt">trunk/LayoutTests/editing/pasteboard/paste-contents-with-side-effects-expected.txt</a></li>
<li><a href="#trunkLayoutTestseditingpasteboardpastecontentswithsideeffectshtml">trunk/LayoutTests/editing/pasteboard/paste-contents-with-side-effects.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (246867 => 246868)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog      2019-06-27 01:28:57 UTC (rev 246867)
+++ trunk/LayoutTests/ChangeLog 2019-06-27 02:55:58 UTC (rev 246868)
</span><span class="lines">@@ -1,3 +1,15 @@
</span><ins>+2019-06-26  Ryosuke Niwa  <rniwa@webkit.org>
+
+        ReplacementFragment should not have script observable side effects
+        https://bugs.webkit.org/show_bug.cgi?id=199147
+
+        Reviewed by Wenson Hsieh.
+
+        Added regression tests.
+
+        * editing/pasteboard/paste-contents-with-side-effects-expected.txt: Added.
+        * editing/pasteboard/paste-contents-with-side-effects.html: Added.
+
</ins><span class="cx"> 2019-06-26  Andy Estes  <aestes@apple.com>
</span><span class="cx"> 
</span><span class="cx">         [Payment Request] Set state to Closed when show() is called during an active session
</span></span></pre></div>
<a id="trunkLayoutTestseditingpasteboardpastecontentswithsideeffectsexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/editing/pasteboard/paste-contents-with-side-effects-expected.txt (0 => 246868)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/editing/pasteboard/paste-contents-with-side-effects-expected.txt                               (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/paste-contents-with-side-effects-expected.txt  2019-06-27 02:55:58 UTC (rev 246868)
</span><span class="lines">@@ -0,0 +1,22 @@
</span><ins>+This tests inserting content with an event handler. WebKit should never execute event handlers.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+
+Inserting with load event handler
+PASS event.dataTransfer.getData('text/html').includes('onload="') is true
+PASS event.dataTransfer.getData('text/html').includes('onmouseover="') is true
+PASS didExecute is false
+
+Inserting with script element
+PASS event.dataTransfer.getData('text/html').includes('script') is true
+PASS didExecute is false
+
+Inserting iframe with a name into plaintext-only
+PASS event.dataTransfer.getData("text/html").includes("iframe name=") is true
+PASS didExecute is false
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestseditingpasteboardpastecontentswithsideeffectshtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/editing/pasteboard/paste-contents-with-side-effects.html (0 => 246868)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/editing/pasteboard/paste-contents-with-side-effects.html                               (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/paste-contents-with-side-effects.html  2019-06-27 02:55:58 UTC (rev 246868)
</span><span class="lines">@@ -0,0 +1,67 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<body>
+<script src="../../resources/js-test.js"></script>
+<div id="editor" contenteditable></div>
+<script>
+
+description('This tests inserting content with an event handler. WebKit should never execute event handlers.');
+
+editor.focus();
+
+function insertHTML(markup) {
+    editor.textContent = '';
+    editor.focus();
+    document.execCommand('insertHTML', false, markup);
+}
+
+let didExecute = false;
+debug('');
+debug('Inserting with load event handler');
+editor.addEventListener('beforeinput', () => {
+    shouldBeTrue(`event.dataTransfer.getData('text/html').includes('onload="')`);
+    shouldBeTrue(`event.dataTransfer.getData('text/html').includes('onmouseover="')`);
+}, {once: true});
+insertHTML('<iframe onload="didExecute = true" onmouseover="alert(\'FAIL\')"></iframe>');
+shouldBeFalse('didExecute');
+
+didExecute = false;
+debug('');
+debug('Inserting with script element');
+editor.addEventListener('beforeinput', () => {
+    shouldBeTrue(`event.dataTransfer.getData('text/html').includes('script')`);
+}, {once: true});
+insertHTML(`<iframe src="data:text/html,<!DOCTYPE html><b>hi</b><script>alert("FAIL")</scr` + 'ipt>"></iframe>');
+shouldBeFalse('didExecute');
+
+didExecute = false;
+debug('');
+debug('Inserting iframe with a name into plaintext-only');
+editor.setAttribute('contenteditable', 'plaintext-only');
+
+let i = 0;
+function insertObjectElement() {
+    const object = document.createElement('object');
+    object.data = 'about:blank';
+    object.onload = () => {
+        try {
+            if (window.open('about:blank', 'named-frame').frameElement.parentNode)
+                didExecute = true;
+        } catch (e) { }
+        if (!didExecute)
+            insertObjectElement();
+    }
+    document.body.appendChild(object);
+}
+insertObjectElement();
+editor.focus();
+editor.addEventListener('beforeinput', () => {
+    shouldBeTrue(`event.dataTransfer.getData("text/html").includes("iframe name=")`);
+}, {once: true});
+insertHTML(`<iframe name='named-frame'></iframe>`);
+shouldBeFalse('didExecute');
+didExecute = true;
+
+</script>
+</body>
+</html>
</ins></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (246867 => 246868)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog   2019-06-27 01:28:57 UTC (rev 246867)
+++ trunk/Source/WebCore/ChangeLog      2019-06-27 02:55:58 UTC (rev 246868)
</span><span class="lines">@@ -1,3 +1,31 @@
</span><ins>+2019-06-26  Ryosuke Niwa  <rniwa@webkit.org>
+
+        ReplacementFragment should not have script observable side effects
+        https://bugs.webkit.org/show_bug.cgi?id=199147
+
+        Reviewed by Wenson Hsieh.
+
+        Fixed the bug that ReplacementFragment has script observable side effects.
+
+        Use a brand new document for sanitization where the script is disabled for test rendering,
+        and remove style and script elements as well as event handlers before the test rendering
+        and the actual pasting.
+
+        Test: editing/pasteboard/paste-contents-with-side-effects.html
+
+        * editing/ReplaceSelectionCommand.cpp:
+        (WebCore::ReplacementFragment::document): Deleted.
+        (WebCore::ReplacementFragment::ReplacementFragment): Use createPageForSanitizingWebContent
+        to create our own document for test rendering. We need to copy over the computed style
+        from the root editable element (editing host) to respect whitespace treatment, etc...
+        (WebCore::ReplacementFragment::removeContentsWithSideEffects): Moved from removeHeadContents.
+        Now removes event handlers and JavaScript URLs.
+        (WebCore::ReplacementFragment::insertFragmentForTestRendering): Renamed variable names.
+        (WebCore::ReplaceSelectionCommand::willApplyCommand): Create the plain text and HTML markup
+        for beforeinput and input events before ReplacementFragment removes contents with side effects.
+        (WebCore::ReplaceSelectionCommand::ensureReplacementFragment): The removal of head elements
+        is now done in ReplacementFragment's constructor.
+
</ins><span class="cx"> 2019-06-26  Andy Estes  <aestes@apple.com>
</span><span class="cx"> 
</span><span class="cx">         [Payment Request] Set state to Closed when show() is called during an active session
</span></span></pre></div>
<a id="trunkSourceWebCoreeditingReplaceSelectionCommandcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/editing/ReplaceSelectionCommand.cpp (246867 => 246868)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/editing/ReplaceSelectionCommand.cpp 2019-06-27 01:28:57 UTC (rev 246867)
+++ trunk/Source/WebCore/editing/ReplaceSelectionCommand.cpp    2019-06-27 02:55:58 UTC (rev 246868)
</span><span class="lines">@@ -31,6 +31,7 @@
</span><span class="cx"> #include "ApplyStyleCommand.h"
</span><span class="cx"> #include "BeforeTextInsertedEvent.h"
</span><span class="cx"> #include "BreakBlockquoteCommand.h"
</span><ins>+#include "CSSComputedStyleDeclaration.h"
</ins><span class="cx"> #include "CSSStyleDeclaration.h"
</span><span class="cx"> #include "DOMWrapperWorld.h"
</span><span class="cx"> #include "DataTransfer.h"
</span><span class="lines">@@ -44,6 +45,7 @@
</span><span class="cx"> #include "FrameSelection.h"
</span><span class="cx"> #include "HTMLBRElement.h"
</span><span class="cx"> #include "HTMLBaseElement.h"
</span><ins>+#include "HTMLBodyElement.h"
</ins><span class="cx"> #include "HTMLInputElement.h"
</span><span class="cx"> #include "HTMLLIElement.h"
</span><span class="cx"> #include "HTMLLinkElement.h"
</span><span class="lines">@@ -55,6 +57,7 @@
</span><span class="cx"> #include "NodeRenderStyle.h"
</span><span class="cx"> #include "RenderInline.h"
</span><span class="cx"> #include "RenderText.h"
</span><ins>+#include "ScriptElement.h"
</ins><span class="cx"> #include "SimplifyMarkupCommand.h"
</span><span class="cx"> #include "SmartReplace.h"
</span><span class="cx"> #include "StyleProperties.h"
</span><span class="lines">@@ -71,8 +74,6 @@
</span><span class="cx"> 
</span><span class="cx"> enum EFragmentType { EmptyFragment, SingleTextNodeFragment, TreeFragment };
</span><span class="cx"> 
</span><del>-static void removeHeadContents(ReplacementFragment&);
-
</del><span class="cx"> // --- ReplacementFragment helper class
</span><span class="cx"> 
</span><span class="cx"> class ReplacementFragment {
</span><span class="lines">@@ -79,7 +80,7 @@
</span><span class="cx">     WTF_MAKE_FAST_ALLOCATED;
</span><span class="cx">     WTF_MAKE_NONCOPYABLE(ReplacementFragment);
</span><span class="cx"> public:
</span><del>-    ReplacementFragment(Document&, DocumentFragment*, const VisibleSelection&);
</del><ins>+    ReplacementFragment(DocumentFragment*, const VisibleSelection&);
</ins><span class="cx"> 
</span><span class="cx">     DocumentFragment* fragment() { return m_fragment.get(); }
</span><span class="cx"> 
</span><span class="lines">@@ -95,6 +96,7 @@
</span><span class="cx">     void removeNodePreservingChildren(Node&);
</span><span class="cx"> 
</span><span class="cx"> private:
</span><ins>+    void removeContentsWithSideEffects();
</ins><span class="cx">     Ref<HTMLElement> insertFragmentForTestRendering(Node* rootEditableNode);
</span><span class="cx">     void removeUnrenderedNodes(Node*);
</span><span class="cx">     void restoreAndRemoveTestRenderingNodesToFragment(StyledElement*);
</span><span class="lines">@@ -102,9 +104,6 @@
</span><span class="cx">     
</span><span class="cx">     void insertNodeBefore(Node&, Node& refNode);
</span><span class="cx"> 
</span><del>-    Document& document() { return *m_document; }
-
-    RefPtr<Document> m_document;
</del><span class="cx">     RefPtr<DocumentFragment> m_fragment;
</span><span class="cx">     bool m_hasInterchangeNewlineAtStart;
</span><span class="cx">     bool m_hasInterchangeNewlineAtEnd;
</span><span class="lines">@@ -152,9 +151,8 @@
</span><span class="cx">     return position;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-ReplacementFragment::ReplacementFragment(Document& document, DocumentFragment* fragment, const VisibleSelection& selection)
-    : m_document(&document)
-    , m_fragment(fragment)
</del><ins>+ReplacementFragment::ReplacementFragment(DocumentFragment* fragment, const VisibleSelection& selection)
+    : m_fragment(fragment)
</ins><span class="cx">     , m_hasInterchangeNewlineAtStart(false)
</span><span class="cx">     , m_hasInterchangeNewlineAtEnd(false)
</span><span class="cx"> {
</span><span class="lines">@@ -162,12 +160,14 @@
</span><span class="cx">         return;
</span><span class="cx">     if (!m_fragment->firstChild())
</span><span class="cx">         return;
</span><del>-    
</del><ins>+
+    removeContentsWithSideEffects();
+
</ins><span class="cx">     RefPtr<Element> editableRoot = selection.rootEditableElement();
</span><span class="cx">     ASSERT(editableRoot);
</span><span class="cx">     if (!editableRoot)
</span><span class="cx">         return;
</span><del>-    
</del><ins>+
</ins><span class="cx">     auto* shadowHost = editableRoot->shadowHost();
</span><span class="cx">     if (!editableRoot->attributeEventListener(eventNames().webkitBeforeTextInsertedEvent, mainThreadNormalWorld())
</span><span class="cx">         && !(shadowHost && shadowHost->renderer() && shadowHost->renderer()->isTextControl())
</span><span class="lines">@@ -176,7 +176,14 @@
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    RefPtr<StyledElement> holder = insertFragmentForTestRendering(editableRoot.get());
</del><ins>+    auto page = createPageForSanitizingWebContent();
+    Document* stagingDocument = page->mainFrame().document();
+    ASSERT(stagingDocument->body());
+
+    ComputedStyleExtractor computedStyleOfEditableRoot(editableRoot.get());
+    stagingDocument->body()->setAttributeWithoutSynchronization(styleAttr, computedStyleOfEditableRoot.copyProperties()->asText());
+
+    RefPtr<StyledElement> holder = insertFragmentForTestRendering(stagingDocument->body());
</ins><span class="cx">     if (!holder) {
</span><span class="cx">         removeInterchangeNodes(m_fragment.get());
</span><span class="cx">         return;
</span><span class="lines">@@ -203,7 +210,7 @@
</span><span class="cx">         if (!m_fragment->firstChild())
</span><span class="cx">             return;
</span><span class="cx"> 
</span><del>-        holder = insertFragmentForTestRendering(editableRoot.get());
</del><ins>+        holder = insertFragmentForTestRendering(stagingDocument->body());
</ins><span class="cx">         removeInterchangeNodes(holder.get());
</span><span class="cx">         removeUnrenderedNodes(holder.get());
</span><span class="cx">         restoreAndRemoveTestRenderingNodesToFragment(holder.get());
</span><span class="lines">@@ -210,6 +217,37 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void ReplacementFragment::removeContentsWithSideEffects()
+{
+    Vector<Ref<Element>> elementsToRemove;
+    Vector<std::pair<Ref<Element>, QualifiedName>> attributesToRemove;
+
+    auto it = descendantsOfType<Element>(*m_fragment).begin();
+    auto end = descendantsOfType<Element>(*m_fragment).end();
+    while (it != end) {
+        auto element = makeRef(*it);
+        if (isScriptElement(element) || (is<HTMLStyleElement>(element) && element->getAttribute(classAttr) != WebKitMSOListQuirksStyle)
+            || is<HTMLBaseElement>(element) || is<HTMLLinkElement>(element) || is<HTMLMetaElement>(element) || is<HTMLTitleElement>(element)) {
+            elementsToRemove.append(WTFMove(element));
+            it.traverseNextSkippingChildren();
+            continue;
+        }
+        if (element->hasAttributes()) {
+            for (auto& attribute : element->attributesIterator()) {
+                if (element->isEventHandlerAttribute(attribute) || element->isJavaScriptURLAttribute(attribute))
+                    attributesToRemove.append({ element.copyRef(), attribute.name() });
+            }
+        }
+        ++it;
+    }
+
+    for (auto& element : elementsToRemove)
+        removeNode(WTFMove(element));
+
+    for (auto& item : attributesToRemove)
+        item.first->removeAttribute(item.second);
+}
+
</ins><span class="cx"> bool ReplacementFragment::isEmpty() const
</span><span class="cx"> {
</span><span class="cx">     return (!m_fragment || !m_fragment->firstChild()) && !m_hasInterchangeNewlineAtStart && !m_hasInterchangeNewlineAtEnd;
</span><span class="lines">@@ -253,13 +291,14 @@
</span><span class="cx">     parent->insertBefore(node, &refNode);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-Ref<HTMLElement> ReplacementFragment::insertFragmentForTestRendering(Node* rootEditableElement)
</del><ins>+Ref<HTMLElement> ReplacementFragment::insertFragmentForTestRendering(Node* rootNode)
</ins><span class="cx"> {
</span><del>-    auto holder = createDefaultParagraphElement(document());
</del><ins>+    auto document = makeRef(rootNode->document());
+    auto holder = createDefaultParagraphElement(document.get());
</ins><span class="cx"> 
</span><span class="cx">     holder->appendChild(*m_fragment);
</span><del>-    rootEditableElement->appendChild(holder);
-    document().updateLayoutIgnorePendingStylesheets();
</del><ins>+    rootNode->appendChild(holder);
+    document->updateLayoutIgnorePendingStylesheets();
</ins><span class="cx"> 
</span><span class="cx">     return holder;
</span><span class="cx"> }
</span><span class="lines">@@ -727,29 +766,6 @@
</span><span class="cx">     return m_startOfInsertedContent;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static void removeHeadContents(ReplacementFragment& fragment)
-{
-    if (fragment.isEmpty())
-        return;
-
-    Vector<Element*> toRemove;
-
-    auto it = descendantsOfType<Element>(*fragment.fragment()).begin();
-    auto end = descendantsOfType<Element>(*fragment.fragment()).end();
-    while (it != end) {
-        if (is<HTMLBaseElement>(*it) || is<HTMLLinkElement>(*it) || is<HTMLMetaElement>(*it) || is<HTMLTitleElement>(*it)
-            || (is<HTMLStyleElement>(*it) && it->getAttribute(classAttr) != WebKitMSOListQuirksStyle)) {
-            toRemove.append(&*it);
-            it.traverseNextSkippingChildren();
-            continue;
-        }
-        ++it;
-    }
-
-    for (auto& element : toRemove)
-        fragment.removeNode(*element);
-}
-
</del><span class="cx"> // Remove style spans before insertion if they are unnecessary.  It's faster because we'll 
</span><span class="cx"> // avoid doing a layout.
</span><span class="cx"> static bool handleStyleSpansBeforeInsertion(ReplacementFragment& fragment, const Position& insertionPos)
</span><span class="lines">@@ -920,9 +936,9 @@
</span><span class="cx"> 
</span><span class="cx"> bool ReplaceSelectionCommand::willApplyCommand()
</span><span class="cx"> {
</span><del>-    ensureReplacementFragment();
</del><span class="cx">     m_documentFragmentPlainText = m_documentFragment->textContent();
</span><span class="cx">     m_documentFragmentHTMLMarkup = serializeFragment(*m_documentFragment, SerializedNodes::SubtreeIncludingNode);
</span><ins>+    ensureReplacementFragment();
</ins><span class="cx">     return CompositeEditCommand::willApplyCommand();
</span><span class="cx"> }
</span><span class="cx">     
</span><span class="lines">@@ -1614,11 +1630,8 @@
</span><span class="cx"> 
</span><span class="cx"> ReplacementFragment* ReplaceSelectionCommand::ensureReplacementFragment()
</span><span class="cx"> {
</span><del>-    if (!m_replacementFragment) {
-        m_replacementFragment = std::make_unique<ReplacementFragment>(document(), m_documentFragment.get(), endingSelection());
-        removeHeadContents(*m_replacementFragment);
-    }
-
</del><ins>+    if (!m_replacementFragment)
+        m_replacementFragment = std::make_unique<ReplacementFragment>(m_documentFragment.get(), endingSelection());
</ins><span class="cx">     return m_replacementFragment.get();
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre>
</div>
</div>

</body>
</html>