summaryrefslogtreecommitdiff
path: root/Source/WebCore/dom/MutationObserver.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/dom/MutationObserver.cpp
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/WebCore/dom/MutationObserver.cpp')
-rw-r--r--Source/WebCore/dom/MutationObserver.cpp197
1 files changed, 127 insertions, 70 deletions
diff --git a/Source/WebCore/dom/MutationObserver.cpp b/Source/WebCore/dom/MutationObserver.cpp
index bf00fac40..0b4b1f90d 100644
--- a/Source/WebCore/dom/MutationObserver.cpp
+++ b/Source/WebCore/dom/MutationObserver.cpp
@@ -32,9 +32,10 @@
#include "MutationObserver.h"
-#include "Dictionary.h"
#include "Document.h"
#include "ExceptionCode.h"
+#include "HTMLSlotElement.h"
+#include "Microtasks.h"
#include "MutationCallback.h"
#include "MutationObserverRegistration.h"
#include "MutationRecord.h"
@@ -45,14 +46,14 @@ namespace WebCore {
static unsigned s_observerPriority = 0;
-PassRefPtr<MutationObserver> MutationObserver::create(PassRefPtr<MutationCallback> callback)
+Ref<MutationObserver> MutationObserver::create(Ref<MutationCallback>&& callback)
{
ASSERT(isMainThread());
- return adoptRef(new MutationObserver(callback));
+ return adoptRef(*new MutationObserver(WTFMove(callback)));
}
-MutationObserver::MutationObserver(PassRefPtr<MutationCallback> callback)
- : m_callback(callback)
+MutationObserver::MutationObserver(Ref<MutationCallback>&& callback)
+ : m_callback(WTFMove(callback))
, m_priority(s_observerPriority++)
{
}
@@ -70,46 +71,43 @@ bool MutationObserver::validateOptions(MutationObserverOptions options)
&& ((options & CharacterData) || !(options & CharacterDataOldValue));
}
-void MutationObserver::observe(Node* node, const Dictionary& optionsDictionary, ExceptionCode& ec)
+ExceptionOr<void> MutationObserver::observe(Node& node, const Init& init)
{
- if (!node) {
- ec = NOT_FOUND_ERR;
- return;
- }
-
- static const struct {
- const char* name;
- MutationObserverOptions value;
- } booleanOptions[] = {
- { "childList", ChildList },
- { "attributes", Attributes },
- { "characterData", CharacterData },
- { "subtree", Subtree },
- { "attributeOldValue", AttributeOldValue },
- { "characterDataOldValue", CharacterDataOldValue }
- };
MutationObserverOptions options = 0;
- for (unsigned i = 0; i < sizeof(booleanOptions) / sizeof(booleanOptions[0]); ++i) {
- bool value = false;
- if (optionsDictionary.get(booleanOptions[i].name, value) && value)
- options |= booleanOptions[i].value;
- }
+
+ if (init.childList)
+ options |= ChildList;
+ if (init.subtree)
+ options |= Subtree;
+ if (init.attributeOldValue.value_or(false))
+ options |= AttributeOldValue;
+ if (init.characterDataOldValue.value_or(false))
+ options |= CharacterDataOldValue;
HashSet<AtomicString> attributeFilter;
- if (optionsDictionary.get("attributeFilter", attributeFilter))
+ if (init.attributeFilter) {
+ for (auto& value : init.attributeFilter.value())
+ attributeFilter.add(value);
options |= AttributeFilter;
-
- if (!validateOptions(options)) {
- ec = SYNTAX_ERR;
- return;
}
- node->registerMutationObserver(this, options, attributeFilter);
+ if (init.attributes ? init.attributes.value() : (options & (AttributeFilter | AttributeOldValue)))
+ options |= Attributes;
+
+ if (init.characterData ? init.characterData.value() : (options & CharacterDataOldValue))
+ options |= CharacterData;
+
+ if (!validateOptions(options))
+ return Exception { TypeError };
+
+ node.registerMutationObserver(*this, options, attributeFilter);
+
+ return { };
}
-Vector<RefPtr<MutationRecord>> MutationObserver::takeRecords()
+Vector<Ref<MutationRecord>> MutationObserver::takeRecords()
{
- Vector<RefPtr<MutationRecord>> records;
+ Vector<Ref<MutationRecord>> records;
records.swap(m_records);
return records;
}
@@ -118,60 +116,100 @@ void MutationObserver::disconnect()
{
m_records.clear();
HashSet<MutationObserverRegistration*> registrations(m_registrations);
- for (HashSet<MutationObserverRegistration*>::iterator iter = registrations.begin(); iter != registrations.end(); ++iter)
- MutationObserverRegistration::unregisterAndDelete(*iter);
+ for (auto* registration : registrations)
+ registration->node().unregisterMutationObserver(*registration);
}
-void MutationObserver::observationStarted(MutationObserverRegistration* registration)
+void MutationObserver::observationStarted(MutationObserverRegistration& registration)
{
- ASSERT(!m_registrations.contains(registration));
- m_registrations.add(registration);
+ ASSERT(!m_registrations.contains(&registration));
+ m_registrations.add(&registration);
}
-void MutationObserver::observationEnded(MutationObserverRegistration* registration)
+void MutationObserver::observationEnded(MutationObserverRegistration& registration)
{
- ASSERT(m_registrations.contains(registration));
- m_registrations.remove(registration);
+ ASSERT(m_registrations.contains(&registration));
+ m_registrations.remove(&registration);
}
typedef HashSet<RefPtr<MutationObserver>> MutationObserverSet;
static MutationObserverSet& activeMutationObservers()
{
- DEFINE_STATIC_LOCAL(MutationObserverSet, activeObservers, ());
+ static NeverDestroyed<MutationObserverSet> activeObservers;
return activeObservers;
}
static MutationObserverSet& suspendedMutationObservers()
{
- DEFINE_STATIC_LOCAL(MutationObserverSet, suspendedObservers, ());
+ static NeverDestroyed<MutationObserverSet> suspendedObservers;
return suspendedObservers;
}
-void MutationObserver::enqueueMutationRecord(PassRefPtr<MutationRecord> mutation)
+// https://dom.spec.whatwg.org/#signal-slot-list
+static Vector<RefPtr<HTMLSlotElement>>& signalSlotList()
+{
+ static NeverDestroyed<Vector<RefPtr<HTMLSlotElement>>> list;
+ return list;
+}
+
+static bool mutationObserverCompoundMicrotaskQueuedFlag;
+
+class MutationObserverMicrotask final : public Microtask {
+ WTF_MAKE_FAST_ALLOCATED;
+private:
+ Result run() final
+ {
+ MutationObserver::notifyMutationObservers();
+ return Result::Done;
+ }
+};
+
+static void queueMutationObserverCompoundMicrotask()
+{
+ if (mutationObserverCompoundMicrotaskQueuedFlag)
+ return;
+ mutationObserverCompoundMicrotaskQueuedFlag = true;
+ MicrotaskQueue::mainThreadQueue().append(std::make_unique<MutationObserverMicrotask>());
+}
+
+void MutationObserver::enqueueMutationRecord(Ref<MutationRecord>&& mutation)
{
ASSERT(isMainThread());
- m_records.append(mutation);
+ m_records.append(WTFMove(mutation));
activeMutationObservers().add(this);
+
+ queueMutationObserverCompoundMicrotask();
+}
+
+void MutationObserver::enqueueSlotChangeEvent(HTMLSlotElement& slot)
+{
+ ASSERT(isMainThread());
+ ASSERT(!signalSlotList().contains(&slot));
+ signalSlotList().append(&slot);
+
+ queueMutationObserverCompoundMicrotask();
}
void MutationObserver::setHasTransientRegistration()
{
ASSERT(isMainThread());
activeMutationObservers().add(this);
+
+ queueMutationObserverCompoundMicrotask();
}
-HashSet<Node*> MutationObserver::getObservedNodes() const
+HashSet<Node*> MutationObserver::observedNodes() const
{
HashSet<Node*> observedNodes;
- for (HashSet<MutationObserverRegistration*>::const_iterator iter = m_registrations.begin(); iter != m_registrations.end(); ++iter)
- (*iter)->addRegistrationNodesToSet(observedNodes);
+ for (auto* registration : m_registrations)
+ registration->addRegistrationNodesToSet(observedNodes);
return observedNodes;
}
bool MutationObserver::canDeliver()
{
- return !m_callback->scriptExecutionContext()->activeDOMObjectsAreSuspended();
+ return m_callback->canInvokeCallback();
}
void MutationObserver::deliver()
@@ -181,24 +219,28 @@ void MutationObserver::deliver()
// Calling clearTransientRegistrations() can modify m_registrations, so it's necessary
// to make a copy of the transient registrations before operating on them.
Vector<MutationObserverRegistration*, 1> transientRegistrations;
- for (HashSet<MutationObserverRegistration*>::iterator iter = m_registrations.begin(); iter != m_registrations.end(); ++iter) {
- if ((*iter)->hasTransientRegistrations())
- transientRegistrations.append(*iter);
+ for (auto* registration : m_registrations) {
+ if (registration->hasTransientRegistrations())
+ transientRegistrations.append(registration);
}
- for (size_t i = 0; i < transientRegistrations.size(); ++i)
- transientRegistrations[i]->clearTransientRegistrations();
+ for (auto& registration : transientRegistrations)
+ registration->clearTransientRegistrations();
if (m_records.isEmpty())
return;
- Vector<RefPtr<MutationRecord>> records;
+ Vector<Ref<MutationRecord>> records;
records.swap(m_records);
m_callback->call(records, this);
}
-void MutationObserver::deliverAllMutations()
+void MutationObserver::notifyMutationObservers()
{
+ // https://dom.spec.whatwg.org/#notify-mutation-observers
+ // 1. Unset mutation observer compound microtask queued flag.
+ mutationObserverCompoundMicrotaskQueuedFlag = false;
+
ASSERT(isMainThread());
static bool deliveryInProgress = false;
if (deliveryInProgress)
@@ -208,29 +250,44 @@ void MutationObserver::deliverAllMutations()
if (!suspendedMutationObservers().isEmpty()) {
Vector<RefPtr<MutationObserver>> suspended;
copyToVector(suspendedMutationObservers(), suspended);
- for (size_t i = 0; i < suspended.size(); ++i) {
- if (!suspended[i]->canDeliver())
+ for (auto& observer : suspended) {
+ if (!observer->canDeliver())
continue;
- suspendedMutationObservers().remove(suspended[i]);
- activeMutationObservers().add(suspended[i]);
+ suspendedMutationObservers().remove(observer);
+ activeMutationObservers().add(observer);
}
}
- while (!activeMutationObservers().isEmpty()) {
- Vector<RefPtr<MutationObserver>> observers;
- copyToVector(activeMutationObservers(), observers);
+ while (!activeMutationObservers().isEmpty() || !signalSlotList().isEmpty()) {
+ // 2. Let notify list be a copy of unit of related similar-origin browsing contexts' list of MutationObserver objects.
+ Vector<RefPtr<MutationObserver>> notifyList;
+ copyToVector(activeMutationObservers(), notifyList);
activeMutationObservers().clear();
- std::sort(observers.begin(), observers.end(), [](const RefPtr<MutationObserver>& lhs, const RefPtr<MutationObserver>& rhs) {
+ std::sort(notifyList.begin(), notifyList.end(), [](auto& lhs, auto& rhs) {
return lhs->m_priority < rhs->m_priority;
});
- for (size_t i = 0; i < observers.size(); ++i) {
- if (observers[i]->canDeliver())
- observers[i]->deliver();
+ // 3. Let signalList be a copy of unit of related similar-origin browsing contexts' signal slot list.
+ // 4. Empty unit of related similar-origin browsing contexts' signal slot list.
+ Vector<RefPtr<HTMLSlotElement>> slotList;
+ if (!signalSlotList().isEmpty()) {
+ slotList.swap(signalSlotList());
+ for (auto& slot : slotList)
+ slot->didRemoveFromSignalSlotList();
+ }
+
+ // 5. For each MutationObserver object mo in notify list, execute a compound microtask subtask
+ for (auto& observer : notifyList) {
+ if (observer->canDeliver())
+ observer->deliver();
else
- suspendedMutationObservers().add(observers[i]);
+ suspendedMutationObservers().add(observer);
}
+
+ // 6. For each slot slot in signalList, in order, fire an event named slotchange, with its bubbles attribute set to true, at slot.
+ for (auto& slot : slotList)
+ slot->dispatchSlotChangeEvent();
}
deliveryInProgress = false;