Text manipulation controller should not observe changes in new replacement elements
https://bugs.webkit.org/show_bug.cgi?id=206015
<rdar://problem/58353667>
Reviewed by Tim Horton.
Source/WebCore:
TextManipulationController may insert elements in the process of completing text replacement operations. When
renderers are created for these elements (after the next layout pass), the controller is notified via
TextManipulationController::didCreateRendererForElement, which causes it to begin observing the newly inserted
elements. For certain clients, this may lead to an unending cycle of text manipulation updates as the new
text manipulation items' tokens will be replaced with new tokens, and we never reach a stable state.
To mitigate this, we avoid adding newly visible elements to m_mutatedElements in the case where the newly
visible elements were recently inserted by text replacement. See below for more details.
Test: TextManipulation.CompleteTextManipulationDoesNotCreateMoreTextManipulationItems
* editing/TextManipulationController.cpp:
(WebCore::TextManipulationController::didCreateRendererForElement):
Avoid considering an element that has a new renderer, if it is an element we had just inserted using text
manipulation APIs.
(WebCore::TextManipulationController::replace):
As we iterate over and apply each text replacement, remember the elements we've inserted using a WeakHashSet;
this set is cleared in a queued async task, after which layout should be up to date.
* editing/TextManipulationController.h:
Tools:
* TestWebKitAPI/Tests/WebKitCocoa/TextManipulation.mm:
Add a new API test to verify that we don't fire text manipulation item callbacks due to inserting elements when
completing text manipulation.
(-[TextManipulationDelegate initWithItemCallback]): Deleted.
Remove a stray initializer that was unused (and also doesn't take an ItemCallback, as its name might suggest).
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@254314 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/editing/TextManipulationController.cpp b/Source/WebCore/editing/TextManipulationController.cpp
index 12542a6..cde9a78 100644
--- a/Source/WebCore/editing/TextManipulationController.cpp
+++ b/Source/WebCore/editing/TextManipulationController.cpp
@@ -178,6 +178,9 @@
void TextManipulationController::didCreateRendererForElement(Element& element)
{
+ if (m_recentlyInsertedElements.contains(element))
+ return;
+
if (m_mutatedElements.computesEmpty())
scheduleObservartionUpdate();
@@ -398,7 +401,13 @@
insertionPoint.containerNode()->insertBefore(insertion.child, insertionPoint.computeNodeBeforePosition());
else
insertion.parentIfDifferentFromCommonAncestor->appendChild(insertion.child);
+ if (is<Element>(insertion.child.get()))
+ m_recentlyInsertedElements.add(downcast<Element>(insertion.child.get()));
}
+ m_document->eventLoop().queueTask(TaskSource::InternalAsyncTask, [weakThis = makeWeakPtr(*this)] {
+ if (auto strongThis = weakThis.get())
+ strongThis->m_recentlyInsertedElements.clear();
+ });
return ManipulationResult::Success;
}