Source/WebCore:
Text manipulation should not manipulate nodes out of paragraph range
https://bugs.webkit.org/show_bug.cgi?id=215406

Reviewed by Wenson Hsieh.

TextManipulationController currently does not set correct start path for insertion. Therefore, it does not mark
the nodes on the start path but out of range correctly, and may change position of those nodes by mistake. For
example, in the newly added test, text node "zero" can be moved around even though it is not in range.

API test: TextManipulation.CompleteTextManipulationShouldOnlyChangeNodesInParagraphRange

* editing/TextManipulationController.cpp:
(WebCore::TextManipulationController::replace):

Tools:
Text manipulationshould not manipulate nodes out of paragraph range
https://bugs.webkit.org/show_bug.cgi?id=215406

Reviewed by Wenson Hsieh.

* TestWebKitAPI/Tests/WebKitCocoa/TextManipulation.mm:
(TestWebKitAPI::TEST):


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@266075 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/editing/TextManipulationController.cpp b/Source/WebCore/editing/TextManipulationController.cpp
index bace7c3..ad43870 100644
--- a/Source/WebCore/editing/TextManipulationController.cpp
+++ b/Source/WebCore/editing/TextManipulationController.cpp
@@ -829,8 +829,20 @@
         nodesToRemove.remove(*node);
 
     HashSet<Ref<Node>> reusedOriginalNodes;
-    Vector<NodeEntry> lastTopDownPath;
     Vector<NodeInsertion> insertions;
+    auto startTopDownPath = getPath(commonAncestor.get(), firstContentNode.get());
+    while (!startTopDownPath.isEmpty()) {
+        auto lastNode = startTopDownPath.last();
+        ASSERT(is<ContainerNode>(lastNode.get()));
+        if (!downcast<ContainerNode>(lastNode.get()).hasOneChild())
+            break;
+        nodesToRemove.add(startTopDownPath.takeLast());
+    }
+    auto lastTopDownPath = startTopDownPath.map([&](auto node) -> NodeEntry {
+        reusedOriginalNodes.add(node.copyRef());
+        return { node, node };
+    });
+
     for (size_t index = 0; index < replacementTokens.size(); ++index) {
         auto& replacementToken = replacementTokens[index];
         auto it = tokenExchangeMap.find(replacementToken.identifier);