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]);