Title: [294063] trunk
Revision
294063
Author
[email protected]
Date
2022-05-11 11:35:14 -0700 (Wed, 11 May 2022)

Log Message

[Webpage Translation] Avoid removing elements with no children during text manipulation
https://bugs.webkit.org/show_bug.cgi?id=240287
rdar://91882797

Reviewed by Tim Horton.

After invoking webpage translation on a particular website, the entire page becomes blank and unusable when
scrolling. This happens because of an uncaught _javascript_ exception that's thrown when this page's script
attempts to remove an element from its parent using `p.removeChild(c)`, where the node `p` is not a parent of
the given node `c`; this, in turn, happens because `TextManipulationController` has already unparented `c` from
`p` while performing text replacement during translation.

In this particular case, the former child node `c` is an empty `div` element with no text or children. As such,
it's unnecessary to flag this element for removal in the first place, since doing so isn't necessary to fill in
translated text.

We can avoid this issue by simply skipping over such nodes (i.e. containers that contain no text, no child
elements, and also are not replaced elements) to avoid this and similar compatibility issues that arise when
the DOM is mutated underneath the page, during translation.

Test: TextManipulation.CompleteTextManipulationSkipsEmptyContainers

* editing/TextManipulationController.cpp:
(WebCore::TextManipulationController::replace):
[Webpage Translation] Avoid removing elements with no children during text manipulation
https://bugs.webkit.org/show_bug.cgi?id=240287
rdar://91882797

Reviewed by Tim Horton.

Add a new API test to exercise the change.

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

Canonical link: https://commits.webkit.org/250467@main

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (294062 => 294063)


--- trunk/Source/WebCore/ChangeLog	2022-05-11 18:18:49 UTC (rev 294062)
+++ trunk/Source/WebCore/ChangeLog	2022-05-11 18:35:14 UTC (rev 294063)
@@ -1,3 +1,30 @@
+2022-05-10  Wenson Hsieh  <[email protected]>
+
+        [Webpage Translation] Avoid removing elements with no children during text manipulation
+        https://bugs.webkit.org/show_bug.cgi?id=240287
+        rdar://91882797
+
+        Reviewed by Tim Horton.
+
+        After invoking webpage translation on a particular website, the entire page becomes blank and unusable when
+        scrolling. This happens because of an uncaught _javascript_ exception that's thrown when this page's script
+        attempts to remove an element from its parent using `p.removeChild(c)`, where the node `p` is not a parent of
+        the given node `c`; this, in turn, happens because `TextManipulationController` has already unparented `c` from
+        `p` while performing text replacement during translation.
+
+        In this particular case, the former child node `c` is an empty `div` element with no text or children. As such,
+        it's unnecessary to flag this element for removal in the first place, since doing so isn't necessary to fill in
+        translated text.
+
+        We can avoid this issue by simply skipping over such nodes (i.e. containers that contain no text, no child
+        elements, and also are not replaced elements) to avoid this and similar compatibility issues that arise when
+        the DOM is mutated underneath the page, during translation.
+
+        Test: TextManipulation.CompleteTextManipulationSkipsEmptyContainers
+
+        * editing/TextManipulationController.cpp:
+        (WebCore::TextManipulationController::replace):
+
 2022-05-11  Youenn Fablet  <[email protected]>
 
         Add a webshare quirk for youtube

Modified: trunk/Source/WebCore/editing/TextManipulationController.cpp (294062 => 294063)


--- trunk/Source/WebCore/editing/TextManipulationController.cpp	2022-05-11 18:18:49 UTC (rev 294062)
+++ trunk/Source/WebCore/editing/TextManipulationController.cpp	2022-05-11 18:35:14 UTC (rev 294063)
@@ -791,10 +791,14 @@
         auto content = iterator.currentContent();
         ASSERT(content.node);
 
+        bool isReplacedOrTextContent = content.isReplacedContent || content.isTextContent;
+        if (!isReplacedOrTextContent && is<ContainerNode>(*content.node) && !content.node->hasChildNodes() && content.text.isEmpty())
+            continue;
+
         lastChildOfCommonAncestorInRange = content.node;
         nodesToRemove.add(*content.node);
 
-        if (!content.isReplacedContent && !content.isTextContent)
+        if (!isReplacedOrTextContent)
             continue;
 
         Vector<ManipulationToken> tokensInCurrentNode;

Modified: trunk/Tools/ChangeLog (294062 => 294063)


--- trunk/Tools/ChangeLog	2022-05-11 18:18:49 UTC (rev 294062)
+++ trunk/Tools/ChangeLog	2022-05-11 18:35:14 UTC (rev 294063)
@@ -1,3 +1,16 @@
+2022-05-10  Wenson Hsieh  <[email protected]>
+
+        [Webpage Translation] Avoid removing elements with no children during text manipulation
+        https://bugs.webkit.org/show_bug.cgi?id=240287
+        rdar://91882797
+
+        Reviewed by Tim Horton.
+
+        Add a new API test to exercise the change.
+
+        * TestWebKitAPI/Tests/WebKitCocoa/TextManipulation.mm:
+        (TestWebKitAPI::TEST):
+
 2022-05-10  Jonathan Bedard  <[email protected]>
 
         [git-webkit] Fail quickly for invalid bugzilla credentials

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/TextManipulation.mm (294062 => 294063)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/TextManipulation.mm	2022-05-11 18:18:49 UTC (rev 294062)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/TextManipulation.mm	2022-05-11 18:35:14 UTC (rev 294063)
@@ -3414,6 +3414,46 @@
     EXPECT_WK_STREQ("<span class=\"hidden\">hello</span>", [webView stringByEvaluatingJavaScript:@"document.body.innerHTML"]);
 }
 
+TEST(TextManipulation, CompleteTextManipulationSkipsEmptyContainers)
+{
+    auto delegate = adoptNS([[TextManipulationDelegate alloc] init]);
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 400, 400)]);
+    [webView _setTextManipulationDelegate:delegate.get()];
+    [webView synchronouslyLoadHTMLString:@"<section><a href=''>Guten<img width='50' src=''></section>"
+        "<section><div id='target'></div><div><a href=''>Tag</a></div></section>"];
+
+    done = false;
+    [webView _startTextManipulationsWithConfiguration:nil completion:^{
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+
+    auto items = [delegate items];
+    EXPECT_EQ(items.count, 1UL);
+    EXPECT_EQ(items[0].tokens.count, 3UL);
+    EXPECT_WK_STREQ("Guten", items[0].tokens[0].content);
+    EXPECT_WK_STREQ("[]", items[0].tokens[1].content);
+    EXPECT_WK_STREQ("Tag", items[0].tokens[2].content);
+
+    auto replacement = createItem(items[0].identifier, {
+        { items[0].tokens[0].identifier, @"Good" },
+        { items[0].tokens[2].identifier, @"Day" }
+    });
+
+    done = false;
+    [webView _completeTextManipulationForItems:@[replacement.get()] completion:^(NSArray<NSError *> *errors) {
+        EXPECT_EQ(errors.count, 0UL);
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+
+    EXPECT_WK_STREQ("SECTION", [webView stringByEvaluatingJavaScript:@"document.getElementById('target').parentElement.tagName"]);
+    NSArray<NSString *> *textContents = [webView objectByEvaluatingJavaScript:@"Array.from(document.links).map(a => a.textContent)"];
+    EXPECT_EQ(textContents.count, 2U);
+    EXPECT_WK_STREQ("Good", textContents.firstObject);
+    EXPECT_WK_STREQ("Day", textContents.lastObject);
+}
+
 TEST(TextManipulation, TextManipulationTokenDebugDescription)
 {
     auto token = adoptNS([[_WKTextManipulationToken alloc] init]);
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to