Title: [264305] trunk
Revision
264305
Author
[email protected]
Date
2020-07-13 10:36:21 -0700 (Mon, 13 Jul 2020)

Log Message

Text manipulation does not observe manipulated text after update
https://bugs.webkit.org/show_bug.cgi?id=213318
<rdar://problem/63766703>

Patch by Sihui Liu <[email protected]> on 2020-07-13
Reviewed by Geoffrey Garen.

Source/WebCore:

Make TextManipulationController be aware of content replacement on Text and extract the new content.

Test: TextManipulation.CompleteTextManipulationForManipulatedTextWithNewContent

* dom/CharacterData.h:
* dom/Text.cpp:
(WebCore::Text::setDataAndUpdate):
* dom/Text.h:
* editing/TextManipulationController.cpp:
(WebCore::TextManipulationController::didCreateRendererForElement):
(WebCore::TextManipulationController::didUpdateContentForText):
(WebCore::TextManipulationController::scheduleObservationUpdate):
* editing/TextManipulationController.h:
* editing/markup.cpp:

Tools:

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

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (264304 => 264305)


--- trunk/Source/WebCore/ChangeLog	2020-07-13 17:35:35 UTC (rev 264304)
+++ trunk/Source/WebCore/ChangeLog	2020-07-13 17:36:21 UTC (rev 264305)
@@ -1,3 +1,26 @@
+2020-07-13  Sihui Liu  <[email protected]>
+
+        Text manipulation does not observe manipulated text after update
+        https://bugs.webkit.org/show_bug.cgi?id=213318
+        <rdar://problem/63766703>
+
+        Reviewed by Geoffrey Garen.
+
+        Make TextManipulationController be aware of content replacement on Text and extract the new content.
+
+        Test: TextManipulation.CompleteTextManipulationForManipulatedTextWithNewContent
+
+        * dom/CharacterData.h:
+        * dom/Text.cpp:
+        (WebCore::Text::setDataAndUpdate):
+        * dom/Text.h:
+        * editing/TextManipulationController.cpp:
+        (WebCore::TextManipulationController::didCreateRendererForElement):
+        (WebCore::TextManipulationController::didUpdateContentForText):
+        (WebCore::TextManipulationController::scheduleObservationUpdate):
+        * editing/TextManipulationController.h:
+        * editing/markup.cpp:
+
 2020-07-13  Keith Miller  <[email protected]>
 
         Clean up SourceProvider and add caller relative load script to jsc.cpp

Modified: trunk/Source/WebCore/dom/CharacterData.h (264304 => 264305)


--- trunk/Source/WebCore/dom/CharacterData.h	2020-07-13 17:35:35 UTC (rev 264304)
+++ trunk/Source/WebCore/dom/CharacterData.h	2020-07-13 17:36:21 UTC (rev 264305)
@@ -33,6 +33,7 @@
     static ptrdiff_t dataMemoryOffset() { return OBJECT_OFFSETOF(CharacterData, m_data); }
 
     WEBCORE_EXPORT void setData(const String&);
+    virtual void setDataAndUpdate(const String&, unsigned offsetOfReplacedData, unsigned oldLength, unsigned newLength);
     unsigned length() const { return m_data.length(); }
     WEBCORE_EXPORT ExceptionOr<String> substringData(unsigned offset, unsigned count);
     WEBCORE_EXPORT void appendData(const String&);
@@ -63,7 +64,6 @@
     String nodeValue() const final;
     ExceptionOr<void> setNodeValue(const String&) final;
     bool virtualIsCharacterData() const final { return true; }
-    void setDataAndUpdate(const String&, unsigned offsetOfReplacedData, unsigned oldLength, unsigned newLength);
     void notifyParentAfterChange(ContainerNode::ChildChangeSource);
 
     String m_data;

Modified: trunk/Source/WebCore/dom/Text.cpp (264304 => 264305)


--- trunk/Source/WebCore/dom/Text.cpp	2020-07-13 17:35:35 UTC (rev 264304)
+++ trunk/Source/WebCore/dom/Text.cpp	2020-07-13 17:36:21 UTC (rev 264305)
@@ -33,6 +33,7 @@
 #include "StyleInheritedData.h"
 #include "StyleResolver.h"
 #include "StyleUpdate.h"
+#include "TextManipulationController.h"
 #include "TextNodeTraversal.h"
 #include <wtf/CheckedArithmetic.h>
 #include <wtf/IsoMallocInlines.h>
@@ -252,4 +253,16 @@
 }
 #endif
 
+void Text::setDataAndUpdate(const String& newData, unsigned offsetOfReplacedData, unsigned oldLength, unsigned newLength)
+{
+    auto oldData = data();
+    CharacterData::setDataAndUpdate(newData, offsetOfReplacedData, oldLength, newLength);
+
+    if (!offsetOfReplacedData) {
+        auto* textManipulationController = document().textManipulationControllerIfExists();
+        if (UNLIKELY(textManipulationController && oldData != newData))
+            textManipulationController->didUpdateContentForText(*this);
+    }
+}
+
 } // namespace WebCore

Modified: trunk/Source/WebCore/dom/Text.h (264304 => 264305)


--- trunk/Source/WebCore/dom/Text.h	2020-07-13 17:35:35 UTC (rev 264304)
+++ trunk/Source/WebCore/dom/Text.h	2020-07-13 17:36:21 UTC (rev 264305)
@@ -57,6 +57,8 @@
 
     String debugDescription() const final;
 
+    void setDataAndUpdate(const String&, unsigned offsetOfReplacedData, unsigned oldLength, unsigned newLength) final;
+
 protected:
     Text(Document& document, const String& data, ConstructionType type)
         : CharacterData(document, data, type)

Modified: trunk/Source/WebCore/editing/TextManipulationController.cpp (264304 => 264305)


--- trunk/Source/WebCore/editing/TextManipulationController.cpp	2020-07-13 17:35:35 UTC (rev 264304)
+++ trunk/Source/WebCore/editing/TextManipulationController.cpp	2020-07-13 17:36:21 UTC (rev 264305)
@@ -508,8 +508,7 @@
     if (m_manipulatedNodes.contains(&element))
         return;
 
-    if (m_elementsWithNewRenderer.computesEmpty())
-        scheduleObservationUpdate();
+    scheduleObservationUpdate();
 
     if (is<PseudoElement>(element)) {
         if (auto* host = downcast<PseudoElement>(element).hostElement())
@@ -518,8 +517,22 @@
         m_elementsWithNewRenderer.add(element);
 }
 
+void TextManipulationController::didUpdateContentForText(Text& text)
+{
+    if (!m_manipulatedNodes.contains(&text))
+        return;
+
+    scheduleObservationUpdate();
+
+    m_manipulatedTextsWithNewContent.add(&text);
+}
+
 void TextManipulationController::scheduleObservationUpdate()
 {
+    // An update is already scheduled.
+    if (!m_manipulatedTextsWithNewContent.isEmpty() || !m_elementsWithNewRenderer.computesEmpty())
+        return;
+
     if (!m_document)
         return;
 
@@ -528,23 +541,30 @@
         if (!controller)
             return;
 
-        HashSet<Ref<Element>> elementsToObserve;
+        HashSet<Ref<Node>> nodesToObserve;
         for (auto& weakElement : controller->m_elementsWithNewRenderer)
-            elementsToObserve.add(weakElement);
+            nodesToObserve.add(weakElement);
         controller->m_elementsWithNewRenderer.clear();
 
-        if (elementsToObserve.isEmpty())
+        for (auto* text : controller->m_manipulatedTextsWithNewContent) {
+            if (!controller->m_manipulatedNodes.contains(text))
+                continue;
+            controller->m_manipulatedNodes.remove(text);
+            nodesToObserve.add(*text);
+        }
+        controller->m_manipulatedTextsWithNewContent.clear();
+
+        if (nodesToObserve.isEmpty())
             return;
 
         RefPtr<Node> commonAncestor;
-        for (auto& element : elementsToObserve) {
+        for (auto& node : nodesToObserve) {
             if (!commonAncestor)
-                commonAncestor = makeRefPtr(element.get());
-            else if (!element->isDescendantOf(commonAncestor.get())) {
-                commonAncestor = commonInclusiveAncestor(*commonAncestor, element.get());
-                ASSERT(commonAncestor);
-            }
+                commonAncestor = is<ContainerNode>(node.get()) ? node.ptr() : node->parentNode();
+            else if (!node->isDescendantOf(commonAncestor.get()))
+                commonAncestor = commonInclusiveAncestor(*commonAncestor, node.get());
         }
+
         auto start = firstPositionInOrBeforeNode(commonAncestor.get());
         auto end = lastPositionInOrAfterNode(commonAncestor.get());
         controller->observeParagraphs(start, end);

Modified: trunk/Source/WebCore/editing/TextManipulationController.h (264304 => 264305)


--- trunk/Source/WebCore/editing/TextManipulationController.h	2020-07-13 17:35:35 UTC (rev 264304)
+++ trunk/Source/WebCore/editing/TextManipulationController.h	2020-07-13 17:36:21 UTC (rev 264305)
@@ -116,6 +116,7 @@
     WEBCORE_EXPORT void startObservingParagraphs(ManipulationItemCallback&&, Vector<ExclusionRule>&& = { });
 
     void didCreateRendererForElement(Element&);
+    void didUpdateContentForText(Text&);
     void removeNode(Node*);
 
     enum class ManipulationFailureType : uint8_t {
@@ -179,6 +180,7 @@
 
     WeakPtr<Document> m_document;
     WeakHashSet<Element> m_elementsWithNewRenderer;
+    HashSet<Text*> m_manipulatedTextsWithNewContent;
     HashSet<Node*> m_manipulatedNodes;
 
     HashMap<String, bool> m_cachedFontFamilyExclusionResults;

Modified: trunk/Source/WebCore/editing/markup.cpp (264304 => 264305)


--- trunk/Source/WebCore/editing/markup.cpp	2020-07-13 17:35:35 UTC (rev 264304)
+++ trunk/Source/WebCore/editing/markup.cpp	2020-07-13 17:36:21 UTC (rev 264305)
@@ -74,6 +74,7 @@
 #include "SocketProvider.h"
 #include "StyleProperties.h"
 #include "TextIterator.h"
+#include "TextManipulationController.h"
 #include "VisibleSelection.h"
 #include "VisibleUnits.h"
 #include <wtf/StdLibExtras.h>

Modified: trunk/Tools/ChangeLog (264304 => 264305)


--- trunk/Tools/ChangeLog	2020-07-13 17:35:35 UTC (rev 264304)
+++ trunk/Tools/ChangeLog	2020-07-13 17:36:21 UTC (rev 264305)
@@ -1,3 +1,14 @@
+2020-07-13  Sihui Liu  <[email protected]>
+
+        Text manipulation does not observe manipulated text after update
+        https://bugs.webkit.org/show_bug.cgi?id=213318
+        <rdar://problem/63766703>
+
+        Reviewed by Geoffrey Garen.
+
+        * TestWebKitAPI/Tests/WebKitCocoa/TextManipulation.mm:
+        (TestWebKitAPI::TEST):
+
 2020-07-13  Zan Dobersek  <[email protected]>
 
         [WPE] Stick to default Glib source priorities in HeadlessViewBackend, WindowViewBackend

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/TextManipulation.mm (264304 => 264305)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/TextManipulation.mm	2020-07-13 17:35:35 UTC (rev 264304)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/TextManipulation.mm	2020-07-13 17:36:21 UTC (rev 264305)
@@ -2713,6 +2713,68 @@
     EXPECT_WK_STREQ("<b>WebKit!</b><span>Hello World<i>Bye</i></span>", [webView stringByEvaluatingJavaScript:@"document.querySelector('div').innerHTML"]);
 }
 
+TEST(TextManipulation, CompleteTextManipulationForManipulatedTextWithNewContent)
+{
+    auto delegate = adoptNS([[TextManipulationDelegate alloc] init]);
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 400, 400)]);
+    [webView _setTextManipulationDelegate:delegate.get()];
+
+    [webView synchronouslyLoadHTMLString:@"<!DOCTYPE html><html>"
+        "<body>"
+            "<span>hello world</span>"
+            "<p>hello webkit</p>"
+        "</body></html>"];
+
+    done = false;
+    [webView _startTextManipulationsWithConfiguration:nil completion:^{
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+
+    auto *items = [delegate items];
+    EXPECT_EQ(items.count, 2UL);
+    EXPECT_EQ(items[0].tokens.count, 1UL);
+    EXPECT_WK_STREQ("hello world", items[0].tokens[0].content);
+    EXPECT_EQ(items[1].tokens.count, 1UL);
+    EXPECT_WK_STREQ("hello webkit", items[1].tokens[0].content);
+
+    done = false;
+    [webView _completeTextManipulationForItems:@[
+        createItem(items[0].identifier, {{ items[0].tokens[0].identifier, @"Hello World" }}).get(),
+        createItem(items[1].identifier, {{ items[1].tokens[0].identifier, @"Hello WebKit" }}).get()
+    ] completion:^(NSArray<NSError *> *errors) {
+        EXPECT_EQ(errors, nil);
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+    EXPECT_WK_STREQ("<span>Hello World</span><p>Hello WebKit</p>", [webView stringByEvaluatingJavaScript:@"document.body.innerHTML"]);
+
+    done = false;
+    delegate.get().itemCallback = ^(_WKTextManipulationItem *item) {
+        if (items.count == 4)
+            done = true;
+    };
+    [webView stringByEvaluatingJavaScript:@"document.querySelector('span').innerHTML='hello world again';"];
+    [webView stringByEvaluatingJavaScript:@"document.querySelector('p').childNodes[0].nodeValue='hello webkit again';"];
+    TestWebKitAPI::Util::run(&done);
+
+    EXPECT_EQ(items[2].tokens.count, 1UL);
+    EXPECT_WK_STREQ("hello world again", items[2].tokens[0].content);
+    EXPECT_EQ(items[3].tokens.count, 1UL);
+    EXPECT_WK_STREQ("hello webkit again", items[3].tokens[0].content);
+
+    done = false;
+    [webView _completeTextManipulationForItems:@[
+        createItem(items[2].identifier, {{ items[2].tokens[0].identifier, @"Hello World Again" }}).get(),
+        createItem(items[3].identifier, {{ items[3].tokens[0].identifier, @"Hello WebKit Again" }}).get()
+    ] completion:^(NSArray<NSError *> *errors) {
+        EXPECT_EQ(errors, nil);
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+    EXPECT_WK_STREQ("<span>Hello World Again</span><p>Hello WebKit Again</p>", [webView stringByEvaluatingJavaScript:@"document.body.innerHTML"]);
+}
+
 TEST(TextManipulation, CompleteTextManipulationAvoidExtractingManipulatedTextAfterManipulation)
 {
     auto delegate = adoptNS([[TextManipulationDelegate alloc] init]);
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to