Title: [290806] trunk
Revision
290806
Author
sihui_...@apple.com
Date
2022-03-03 17:32:11 -0800 (Thu, 03 Mar 2022)

Log Message

Text manipulation does not observe updated title element
https://bugs.webkit.org/show_bug.cgi?id=237435
rdar://87318842

Reviewed by Wenson Hsieh.

Source/WebCore:

TextManipulationController now monitors two types of nodes (after first-time manipulation):
(1) manipulated nodes with content update
(2) non-manipulated nodes (newly displayed or newly added)
We should make sure title element gets added to set (1) if it's newly created, and gets added to set (2) if its
text content is updated.

New test: TextManipulation.CompleteTextManipulationForTitleElement

* dom/Document.cpp:
(WebCore::Document::setTitle):
* dom/Text.cpp:
(WebCore::Text::setDataAndUpdate):
* editing/TextManipulationController.cpp:
(WebCore::TextManipulationController::didUpdateContentForNode):
(WebCore::TextManipulationController::didAddOrCreateRendererForNode):
(WebCore::TextManipulationController::scheduleObservationUpdate):
(WebCore::TextManipulationController::replace):
(WebCore::TextManipulationController::didCreateRendererForElement): Deleted.
(WebCore::TextManipulationController::didUpdateContentForText): Deleted.
(WebCore::TextManipulationController::didCreateRendererForTextNode): Deleted.
* editing/TextManipulationController.h:
* html/HTMLTitleElement.cpp:
* rendering/updating/RenderTreeUpdater.cpp:
(WebCore::RenderTreeUpdater::createRenderer):
(WebCore::RenderTreeUpdater::createTextRenderer):

Tools:

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

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (290805 => 290806)


--- trunk/Source/WebCore/ChangeLog	2022-03-04 01:26:55 UTC (rev 290805)
+++ trunk/Source/WebCore/ChangeLog	2022-03-04 01:32:11 UTC (rev 290806)
@@ -1,3 +1,37 @@
+2022-03-03  Sihui Liu  <sihui_...@apple.com>
+
+        Text manipulation does not observe updated title element
+        https://bugs.webkit.org/show_bug.cgi?id=237435
+        rdar://87318842
+
+        Reviewed by Wenson Hsieh.
+
+        TextManipulationController now monitors two types of nodes (after first-time manipulation): 
+        (1) manipulated nodes with content update 
+        (2) non-manipulated nodes (newly displayed or newly added)
+        We should make sure title element gets added to set (1) if it's newly created, and gets added to set (2) if its
+        text content is updated.
+
+        New test: TextManipulation.CompleteTextManipulationForTitleElement
+
+        * dom/Document.cpp:
+        (WebCore::Document::setTitle):
+        * dom/Text.cpp:
+        (WebCore::Text::setDataAndUpdate):
+        * editing/TextManipulationController.cpp:
+        (WebCore::TextManipulationController::didUpdateContentForNode):
+        (WebCore::TextManipulationController::didAddOrCreateRendererForNode):
+        (WebCore::TextManipulationController::scheduleObservationUpdate):
+        (WebCore::TextManipulationController::replace):
+        (WebCore::TextManipulationController::didCreateRendererForElement): Deleted.
+        (WebCore::TextManipulationController::didUpdateContentForText): Deleted.
+        (WebCore::TextManipulationController::didCreateRendererForTextNode): Deleted.
+        * editing/TextManipulationController.h:
+        * html/HTMLTitleElement.cpp:
+        * rendering/updating/RenderTreeUpdater.cpp:
+        (WebCore::RenderTreeUpdater::createRenderer):
+        (WebCore::RenderTreeUpdater::createTextRenderer):
+
 2022-03-03  Michael Saboff  <msab...@apple.com>
 
         Copy WebKit frameworks and XPC processes to Secondary Path

Modified: trunk/Source/WebCore/dom/Document.cpp (290805 => 290806)


--- trunk/Source/WebCore/dom/Document.cpp	2022-03-04 01:26:55 UTC (rev 290805)
+++ trunk/Source/WebCore/dom/Document.cpp	2022-03-04 01:32:11 UTC (rev 290806)
@@ -1726,6 +1726,7 @@
         if (m_titleElement)
             m_titleElement->setTextContent(title);
     } else if (is<HTMLElement>(element)) {
+        std::optional<String> oldTitle;
         if (!m_titleElement) {
             RefPtr headElement = head();
             if (!headElement)
@@ -1732,10 +1733,21 @@
                 return;
             m_titleElement = HTMLTitleElement::create(HTMLNames::titleTag, *this);
             headElement->appendChild(*m_titleElement);
+        } else
+            oldTitle = m_titleElement->textContent();
+
+        // appendChild above may have run scripts which removed m_titleElement.
+        if (!m_titleElement)
+            return;
+    
+        m_titleElement->setTextContent(title);
+        auto* textManipulationController = textManipulationControllerIfExists();
+        if (UNLIKELY(textManipulationController)) {
+            if (!oldTitle)
+                textManipulationController->didAddOrCreateRendererForNode(*m_titleElement);
+            else if (*oldTitle != title)
+                textManipulationController->didUpdateContentForNode(*m_titleElement);
         }
-        // appendChild above may have ran scripts which removed m_titleElement.
-        if (m_titleElement)
-            m_titleElement->setTextContent(title);
     }
 }
 

Modified: trunk/Source/WebCore/dom/Text.cpp (290805 => 290806)


--- trunk/Source/WebCore/dom/Text.cpp	2022-03-04 01:26:55 UTC (rev 290805)
+++ trunk/Source/WebCore/dom/Text.cpp	2022-03-04 01:32:11 UTC (rev 290806)
@@ -269,7 +269,7 @@
     if (!offsetOfReplacedData) {
         auto* textManipulationController = document().textManipulationControllerIfExists();
         if (UNLIKELY(textManipulationController && oldData != newData))
-            textManipulationController->didUpdateContentForText(*this);
+            textManipulationController->didUpdateContentForNode(*this);
     }
 }
 

Modified: trunk/Source/WebCore/editing/TextManipulationController.cpp (290805 => 290806)


--- trunk/Source/WebCore/editing/TextManipulationController.cpp	2022-03-04 01:26:55 UTC (rev 290805)
+++ trunk/Source/WebCore/editing/TextManipulationController.cpp	2022-03-04 01:32:11 UTC (rev 290806)
@@ -530,40 +530,30 @@
     addItemIfPossible(std::exchange(unitsInCurrentParagraph, { }));
 }
 
-void TextManipulationController::didCreateRendererForElement(Element& element)
+void TextManipulationController::didUpdateContentForNode(Node& node)
 {
-    if (m_manipulatedNodes.contains(element))
+    if (!m_manipulatedNodes.contains(node))
         return;
 
     scheduleObservationUpdate();
 
-    if (is<PseudoElement>(element)) {
-        if (auto* host = downcast<PseudoElement>(element).hostElement())
-            m_elementsWithNewRenderer.add(*host);
-    } else
-        m_elementsWithNewRenderer.add(element);
+    m_manipulatedNodesWithNewContent.add(node);
 }
 
-void TextManipulationController::didUpdateContentForText(Text& text)
+void TextManipulationController::didAddOrCreateRendererForNode(Node& node)
 {
-    if (!m_manipulatedNodes.contains(text))
+    if (m_manipulatedNodes.contains(node))
         return;
 
     scheduleObservationUpdate();
 
-    m_manipulatedTextsWithNewContent.add(text);
+    if (is<PseudoElement>(node)) {
+        if (auto* host = downcast<PseudoElement>(node).hostElement())
+            m_addedOrNewlyRenderedNodes.add(*host);
+    } else
+        m_addedOrNewlyRenderedNodes.add(node);
 }
 
-void TextManipulationController::didCreateRendererForTextNode(Text& text)
-{
-    if (m_manipulatedNodes.contains(text))
-        return;
-
-    scheduleObservationUpdate();
-
-    m_textNodesWithNewRenderer.add(text);
-}
-
 void TextManipulationController::scheduleObservationUpdate()
 {
     if (m_didScheduleObservationUpdate)
@@ -582,21 +572,17 @@
         controller->m_didScheduleObservationUpdate = false;
 
         HashSet<Ref<Node>> nodesToObserve;
-        for (auto& weakElement : controller->m_elementsWithNewRenderer)
-            nodesToObserve.add(weakElement);
-        controller->m_elementsWithNewRenderer.clear();
-
-        for (auto& text : controller->m_manipulatedTextsWithNewContent) {
+        for (auto& text : controller->m_manipulatedNodesWithNewContent) {
             if (!controller->m_manipulatedNodes.contains(text))
                 continue;
             controller->m_manipulatedNodes.remove(text);
             nodesToObserve.add(text);
         }
-        controller->m_manipulatedTextsWithNewContent.clear();
+        controller->m_manipulatedNodesWithNewContent.clear();
 
-        for (auto& text : controller->m_textNodesWithNewRenderer)
-            nodesToObserve.add(text);
-        controller->m_textNodesWithNewRenderer.clear();
+        for (auto& node : controller->m_addedOrNewlyRenderedNodes)
+            nodesToObserve.add(node);
+        controller->m_addedOrNewlyRenderedNodes.clear();
 
         if (nodesToObserve.isEmpty())
             return;
@@ -615,7 +601,15 @@
                 commonAncestor = commonInclusiveAncestor<ComposedTree>(*commonAncestor, node.get());
         }
 
-        auto start = firstPositionInOrBeforeNode(commonAncestor.get());
+        Position start;
+        if (auto* element = downcast<Element>(commonAncestor.get())) {
+            // Ensure to include the element in the range.
+            if (canPerformTextManipulationByReplacingEntireTextContent(*element))
+                start = positionBeforeNode(commonAncestor.get());
+        }
+        if (start.isNull())
+            start = firstPositionInOrBeforeNode(commonAncestor.get());
+
         auto end = lastPositionInOrAfterNode(commonAncestor.get());
         controller->observeParagraphs(start, end);
 
@@ -781,6 +775,8 @@
             downcast<HTMLInputElement>(*element).setValue(newValue.toString());
         else
             element->setAttribute(item.attributeName, newValue.toString());
+
+        m_manipulatedNodes.add(*element);
         return std::nullopt;
     }
 

Modified: trunk/Source/WebCore/editing/TextManipulationController.h (290805 => 290806)


--- trunk/Source/WebCore/editing/TextManipulationController.h	2022-03-04 01:26:55 UTC (rev 290805)
+++ trunk/Source/WebCore/editing/TextManipulationController.h	2022-03-04 01:32:11 UTC (rev 290806)
@@ -115,9 +115,8 @@
     using ManipulationItemCallback = Function<void(Document&, const Vector<ManipulationItem>&)>;
     WEBCORE_EXPORT void startObservingParagraphs(ManipulationItemCallback&&, Vector<ExclusionRule>&& = { });
 
-    void didCreateRendererForElement(Element&);
-    void didCreateRendererForTextNode(Text&);
-    void didUpdateContentForText(Text&);
+    void didUpdateContentForNode(Node&);
+    void didAddOrCreateRendererForNode(Node&);
     void removeNode(Node&);
 
     enum class ManipulationFailureType : uint8_t {
@@ -181,9 +180,10 @@
 
     WeakPtr<Document> m_document;
     WeakHashSet<Element> m_elementsWithNewRenderer;
-    WeakHashSet<Text> m_manipulatedTextsWithNewContent;
     WeakHashSet<Node> m_textNodesWithNewRenderer;
     WeakHashSet<Node> m_manipulatedNodes;
+    WeakHashSet<Node> m_manipulatedNodesWithNewContent;
+    WeakHashSet<Node> m_addedOrNewlyRenderedNodes;
 
     HashMap<String, bool> m_cachedFontFamilyExclusionResults;
 

Modified: trunk/Source/WebCore/html/HTMLTitleElement.cpp (290805 => 290806)


--- trunk/Source/WebCore/html/HTMLTitleElement.cpp	2022-03-04 01:26:55 UTC (rev 290805)
+++ trunk/Source/WebCore/html/HTMLTitleElement.cpp	2022-03-04 01:32:11 UTC (rev 290806)
@@ -32,6 +32,7 @@
 #include "StyleInheritedData.h"
 #include "StyleResolver.h"
 #include "Text.h"
+#include "TextManipulationController.h"
 #include "TextNodeTraversal.h"
 #include <wtf/IsoMallocInlines.h>
 #include <wtf/Ref.h>

Modified: trunk/Source/WebCore/rendering/updating/RenderTreeUpdater.cpp (290805 => 290806)


--- trunk/Source/WebCore/rendering/updating/RenderTreeUpdater.cpp	2022-03-04 01:26:55 UTC (rev 290805)
+++ trunk/Source/WebCore/rendering/updating/RenderTreeUpdater.cpp	2022-03-04 01:32:11 UTC (rev 290806)
@@ -395,7 +395,7 @@
 
     auto* textManipulationController = m_document.textManipulationControllerIfExists();
     if (UNLIKELY(textManipulationController))
-        textManipulationController->didCreateRendererForElement(element);
+        textManipulationController->didAddOrCreateRendererForNode(element);
 
     if (AXObjectCache* cache = m_document.axObjectCache())
         cache->updateCacheAfterNodeIsAttached(&element);
@@ -478,7 +478,7 @@
 
     auto* textManipulationController = m_document.textManipulationControllerIfExists();
     if (UNLIKELY(textManipulationController))
-        textManipulationController->didCreateRendererForTextNode(textNode);
+        textManipulationController->didAddOrCreateRendererForNode(textNode);
 }
 
 void RenderTreeUpdater::updateTextRenderer(Text& text, const Style::TextUpdate* textUpdate)

Modified: trunk/Tools/ChangeLog (290805 => 290806)


--- trunk/Tools/ChangeLog	2022-03-04 01:26:55 UTC (rev 290805)
+++ trunk/Tools/ChangeLog	2022-03-04 01:32:11 UTC (rev 290806)
@@ -1,3 +1,14 @@
+2022-03-03  Sihui Liu  <sihui_...@apple.com>
+
+        Text manipulation does not observe updated title element
+        https://bugs.webkit.org/show_bug.cgi?id=237435
+        rdar://87318842
+
+        Reviewed by Wenson Hsieh.
+
+        * TestWebKitAPI/Tests/WebKitCocoa/TextManipulation.mm:
+        (TestWebKitAPI::TEST):
+
 2022-03-03  Lauro Moura  <lmo...@igalia.com>
 
         [Python3] Switch a few more glib scripts to Python3

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/TextManipulation.mm (290805 => 290806)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/TextManipulation.mm	2022-03-04 01:26:55 UTC (rev 290805)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/TextManipulation.mm	2022-03-04 01:32:11 UTC (rev 290806)
@@ -3025,6 +3025,64 @@
     EXPECT_WK_STREQ("<span>Hello World Again</span><p>Hello WebKit Again</p>", [webView stringByEvaluatingJavaScript:@"document.body.innerHTML"]);
 }
 
+TEST(TextManipulation, CompleteTextManipulationForTitleElement)
+{
+    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></html>"];
+
+    done = false;
+    [webView _startTextManipulationsWithConfiguration:nil completion:^{
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+    auto *items = [delegate items];
+    EXPECT_EQ(items.count, 0UL);
+
+    done = false;
+    [webView stringByEvaluatingJavaScript:@"document.title = 'page title'"];
+    delegate.get().itemCallback = ^(_WKTextManipulationItem *item) {
+        if (items.count == 1)
+            done = true;
+    };
+    TestWebKitAPI::Util::run(&done);
+    EXPECT_EQ(items[0].tokens.count, 1UL);
+    EXPECT_WK_STREQ("page title", items[0].tokens[0].content);
+
+    done = false;
+    [webView _completeTextManipulationForItems:@[
+        createItem(items[0].identifier, {{ items[0].tokens[0].identifier, @"Page Title" }}).get()
+    ] completion:^(NSArray<NSError *> *errors) {
+        EXPECT_EQ(errors, nil);
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+    EXPECT_WK_STREQ("Page Title", [webView stringByEvaluatingJavaScript:@"document.title"]);
+    EXPECT_WK_STREQ("<head><title>Page Title</title></head><body></body>", [webView stringByEvaluatingJavaScript:@"document.documentElement.innerHTML"]);
+
+    done = false;
+    [webView stringByEvaluatingJavaScript:@"document.title = 'new page title'"];
+    delegate.get().itemCallback = ^(_WKTextManipulationItem *item) {
+        if (items.count == 2)
+            done = true;
+    };
+    TestWebKitAPI::Util::run(&done);
+    EXPECT_EQ(items[1].tokens.count, 1UL);
+    EXPECT_WK_STREQ("new page title", items[1].tokens[0].content);
+
+    done = false;
+    [webView _completeTextManipulationForItems:@[
+        createItem(items[1].identifier, {{ items[1].tokens[0].identifier, @"New Page Title" }}).get()
+    ] completion:^(NSArray<NSError *> *errors) {
+        EXPECT_EQ(errors, nil);
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+    EXPECT_WK_STREQ("New Page Title", [webView stringByEvaluatingJavaScript:@"document.title"]);
+    EXPECT_WK_STREQ("<head><title>New Page Title</title></head><body></body>", [webView stringByEvaluatingJavaScript:@"document.documentElement.innerHTML"]);
+}
+
 TEST(TextManipulation, CompleteTextManipulationAvoidExtractingManipulatedTextAfterManipulation)
 {
     auto delegate = adoptNS([[TextManipulationDelegate alloc] init]);
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to