#include "wtf/HashMap.h"
#include "wtf/StdLibExtras.h"
-namespace WebCore {
+namespace blink {
-typedef HashMap<Node*, ChildListMutationAccumulator*> AccumulatorMap;
+// The accumulator map is used to make sure that there is only one mutation
+// accumulator for a given node even if there are multiple ChildListMutationScopes
+// on the stack. The map is always empty when there are no ChildListMutationScopes
+// on the stack.
+typedef WillBeHeapHashMap<RawPtrWillBeMember<Node>, RawPtrWillBeMember<ChildListMutationAccumulator> > AccumulatorMap;
static AccumulatorMap& accumulatorMap()
{
- DEFINE_STATIC_LOCAL(AccumulatorMap, map, ());
- return map;
+ DEFINE_STATIC_LOCAL(OwnPtrWillBePersistent<AccumulatorMap>, map, (adoptPtrWillBeNoop(new AccumulatorMap())));
+ return *map;
}
-ChildListMutationAccumulator::ChildListMutationAccumulator(PassRefPtr<Node> target, PassOwnPtrWillBeRawPtr<MutationObserverInterestGroup> observers)
+ChildListMutationAccumulator::ChildListMutationAccumulator(PassRefPtrWillBeRawPtr<Node> target, PassOwnPtrWillBeRawPtr<MutationObserverInterestGroup> observers)
: m_target(target)
- , m_lastAdded(0)
+ , m_lastAdded(nullptr)
, m_observers(observers)
+ , m_mutationScopes(0)
{
}
-ChildListMutationAccumulator::~ChildListMutationAccumulator()
+void ChildListMutationAccumulator::leaveMutationScope()
{
- if (!isEmpty())
- enqueueMutationRecord();
- accumulatorMap().remove(m_target.get());
+ ASSERT(m_mutationScopes > 0);
+ if (!--m_mutationScopes) {
+ if (!isEmpty())
+ enqueueMutationRecord();
+ accumulatorMap().remove(m_target.get());
+ }
}
-PassRefPtr<ChildListMutationAccumulator> ChildListMutationAccumulator::getOrCreate(Node& target)
+DEFINE_EMPTY_DESTRUCTOR_WILL_BE_REMOVED(ChildListMutationAccumulator);
+
+PassRefPtrWillBeRawPtr<ChildListMutationAccumulator> ChildListMutationAccumulator::getOrCreate(Node& target)
{
- AccumulatorMap::AddResult result = accumulatorMap().add(&target, 0);
- RefPtr<ChildListMutationAccumulator> accumulator;
+ AccumulatorMap::AddResult result = accumulatorMap().add(&target, nullptr);
+ RefPtrWillBeRawPtr<ChildListMutationAccumulator> accumulator;
if (!result.isNewEntry)
accumulator = result.storedValue->value;
else {
- accumulator = adoptRef(new ChildListMutationAccumulator(PassRefPtr<Node>(target), MutationObserverInterestGroup::createForChildListMutation(target)));
+ accumulator = adoptRefWillBeNoop(new ChildListMutationAccumulator(PassRefPtrWillBeRawPtr<Node>(target), MutationObserverInterestGroup::createForChildListMutation(target)));
result.storedValue->value = accumulator.get();
}
return accumulator.release();
return isEmpty() || (m_lastAdded == child->previousSibling() && m_nextSibling == child->nextSibling());
}
-void ChildListMutationAccumulator::childAdded(PassRefPtr<Node> prpChild)
+void ChildListMutationAccumulator::childAdded(PassRefPtrWillBeRawPtr<Node> prpChild)
{
ASSERT(hasObservers());
- RefPtr<Node> child = prpChild;
+ RefPtrWillBeRawPtr<Node> child = prpChild;
if (!isAddedNodeInOrder(child.get()))
enqueueMutationRecord();
return isEmpty() || m_nextSibling == child;
}
-void ChildListMutationAccumulator::willRemoveChild(PassRefPtr<Node> prpChild)
+void ChildListMutationAccumulator::willRemoveChild(PassRefPtrWillBeRawPtr<Node> prpChild)
{
ASSERT(hasObservers());
- RefPtr<Node> child = prpChild;
+ RefPtrWillBeRawPtr<Node> child = prpChild;
if (!m_addedNodes.isEmpty() || !isRemovedNodeInOrder(child.get()))
enqueueMutationRecord();
ASSERT(hasObservers());
ASSERT(!isEmpty());
- RefPtr<NodeList> addedNodes = StaticNodeList::adopt(m_addedNodes);
- RefPtr<NodeList> removedNodes = StaticNodeList::adopt(m_removedNodes);
+ RefPtrWillBeRawPtr<StaticNodeList> addedNodes = StaticNodeList::adopt(m_addedNodes);
+ RefPtrWillBeRawPtr<StaticNodeList> removedNodes = StaticNodeList::adopt(m_removedNodes);
RefPtrWillBeRawPtr<MutationRecord> record = MutationRecord::createChildList(m_target, addedNodes.release(), removedNodes.release(), m_previousSibling.release(), m_nextSibling.release());
m_observers->enqueueMutationRecord(record.release());
- m_lastAdded = 0;
+ m_lastAdded = nullptr;
ASSERT(isEmpty());
}
bool ChildListMutationAccumulator::isEmpty()
{
bool result = m_removedNodes.isEmpty() && m_addedNodes.isEmpty();
-#ifndef NDEBUG
+#if ENABLE(ASSERT)
if (result) {
ASSERT(!m_previousSibling);
ASSERT(!m_nextSibling);
return result;
}
-} // namespace WebCore
+void ChildListMutationAccumulator::trace(Visitor* visitor)
+{
+ visitor->trace(m_target);
+ visitor->trace(m_removedNodes);
+ visitor->trace(m_addedNodes);
+ visitor->trace(m_previousSibling);
+ visitor->trace(m_nextSibling);
+ visitor->trace(m_lastAdded);
+ visitor->trace(m_observers);
+}
+
+} // namespace blink