Index: third_party/WebKit/Source/core/dom/SynchronousMutationNotifier.cpp |
diff --git a/third_party/WebKit/Source/core/dom/SynchronousMutationNotifier.cpp b/third_party/WebKit/Source/core/dom/SynchronousMutationNotifier.cpp |
index 506cdb9409007cfba208fc809df03de25a270a0d..6109889a19c9bfd11ae7a01ce4bcd2e002880c58 100644 |
--- a/third_party/WebKit/Source/core/dom/SynchronousMutationNotifier.cpp |
+++ b/third_party/WebKit/Source/core/dom/SynchronousMutationNotifier.cpp |
@@ -9,7 +9,28 @@ |
namespace blink { |
-SynchronousMutationNotifier::SynchronousMutationNotifier() = default; |
+SynchronousMutationNotifier::ScopedNotificationSuppressor:: |
+ ScopedNotificationSuppressor(SynchronousMutationNotifier* notifier) { |
+ m_notifier = notifier; |
+ m_notifier->incrementSuppressorCount(); |
+} |
+ |
+SynchronousMutationNotifier::ScopedNotificationSuppressor:: |
+ ~ScopedNotificationSuppressor() { |
+ m_notifier->decrementSuppressorCount(); |
+} |
+ |
+SynchronousMutationNotifier::SynchronousMutationNotifier() |
+ : m_suppressorCount(0), |
+ m_pendingCharacterData(nullptr), |
+ m_pendingOffset(0), |
+ m_pendingOldLength(0), |
+ m_pendingNewLength(0) {} |
+ |
+DEFINE_TRACE(SynchronousMutationNotifier) { |
+ visitor->trace(m_pendingCharacterData); |
+ LifecycleNotifier<Document, SynchronousMutationObserver>::trace(visitor); |
+} |
void SynchronousMutationNotifier::notifyChangeChildren( |
const ContainerNode& container) { |
@@ -41,6 +62,32 @@ void SynchronousMutationNotifier::notifyUpdateCharacterData( |
unsigned offset, |
unsigned oldLength, |
unsigned newLength) { |
+ if (m_suppressorCount) { |
+ if (!m_pendingCharacterData) { |
+ m_pendingCharacterData = characterData; |
+ m_pendingOffset = offset; |
+ m_pendingOldLength = oldLength; |
+ m_pendingNewLength = newLength; |
+ return; |
+ } |
+ |
+ if (m_pendingCharacterData == characterData && m_pendingNewLength == 0 && |
+ oldLength == 0 && m_pendingOffset == offset) { |
+ // insert following a delete |
+ m_pendingNewLength = newLength; |
+ return; |
+ } |
+ |
+ // otherwise, flush what we're currently holding and store the new update |
+ // as pending |
+ flushPendingCharacterDataUpdate(); |
+ m_pendingCharacterData = characterData; |
+ m_pendingOffset = offset; |
+ m_pendingOldLength = oldLength; |
+ m_pendingNewLength = newLength; |
+ return; |
+ } |
+ |
for (SynchronousMutationObserver* observer : m_observers) { |
observer->didUpdateCharacterData(characterData, offset, oldLength, |
newLength); |
@@ -58,4 +105,34 @@ void SynchronousMutationNotifier::notifyNodeWillBeRemoved(Node& node) { |
observer->nodeWillBeRemoved(node); |
} |
+void SynchronousMutationNotifier::incrementSuppressorCount() { |
+ m_suppressorCount++; |
+} |
+ |
+void SynchronousMutationNotifier::decrementSuppressorCount() { |
+ m_suppressorCount--; |
+ if (m_suppressorCount == 0) { |
+ flushPendingCharacterDataUpdate(); |
+ } |
+} |
+ |
+void SynchronousMutationNotifier::notifyUpdateCharacterDataImmediately( |
+ CharacterData* characterData, |
+ unsigned offset, |
+ unsigned oldLength, |
+ unsigned newLength) { |
+ for (SynchronousMutationObserver* observer : m_observers) { |
+ observer->didUpdateCharacterData(characterData, offset, oldLength, |
+ newLength); |
+ } |
+} |
+ |
+void SynchronousMutationNotifier::flushPendingCharacterDataUpdate() { |
+ if (!m_pendingCharacterData) |
+ return; |
+ notifyUpdateCharacterDataImmediately(m_pendingCharacterData, m_pendingOffset, |
+ m_pendingOldLength, m_pendingNewLength); |
+ m_pendingCharacterData = nullptr; |
+} |
+ |
} // namespace blink |