blob: e05f34bf1a3922f8973f59dca0c1bf9cd37bde8f [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "core/dom/custom/CustomElementReactionStack.h"
#include "bindings/core/v8/Microtask.h"
#include "core/dom/Element.h"
#include "core/dom/custom/CEReactionsScope.h"
#include "core/dom/custom/CustomElementReactionQueue.h"
#include "core/frame/FrameHost.h"
namespace blink {
// TODO(dominicc): Consider using linked heap structures, avoiding
// finalizers, to make short-lived entries fast.
CustomElementReactionStack::CustomElementReactionStack()
{
}
DEFINE_TRACE(CustomElementReactionStack)
{
visitor->trace(m_map);
visitor->trace(m_stack);
visitor->trace(m_backupQueue);
}
void CustomElementReactionStack::push()
{
m_stack.append(nullptr);
}
void CustomElementReactionStack::popInvokingReactions()
{
ElementQueue* queue = m_stack.last();
if (queue)
invokeReactions(*queue);
m_stack.removeLast();
}
void CustomElementReactionStack::invokeReactions(ElementQueue& queue)
{
for (size_t i = 0; i < queue.size(); ++i) {
Element* element = queue[i];
if (CustomElementReactionQueue* reactions = m_map.get(element)) {
reactions->invokeReactions(element);
CHECK(reactions->isEmpty());
m_map.remove(element);
}
}
}
void CustomElementReactionStack::enqueueToCurrentQueue(
Element* element,
CustomElementReaction* reaction)
{
enqueue(m_stack.last(), element, reaction);
}
void CustomElementReactionStack::enqueue(
Member<ElementQueue>& queue,
Element* element,
CustomElementReaction* reaction)
{
if (!queue)
queue = new ElementQueue();
queue->append(element);
CustomElementReactionQueue* reactions = m_map.get(element);
if (!reactions) {
reactions = new CustomElementReactionQueue();
m_map.add(element, reactions);
}
reactions->add(reaction);
}
void CustomElementReactionStack::enqueueToBackupQueue(
Element* element,
CustomElementReaction* reaction)
{
// https://html.spec.whatwg.org/multipage/scripting.html#backup-element-queue
DCHECK(!CEReactionsScope::current());
DCHECK(m_stack.isEmpty());
DCHECK(isMainThread());
// If the processing the backup element queue is not set:
if (!m_backupQueue || m_backupQueue->isEmpty()) {
Microtask::enqueueMicrotask(WTF::bind(
&CustomElementReactionStack::invokeBackupQueue,
Persistent<CustomElementReactionStack>(this)));
}
enqueue(m_backupQueue, element, reaction);
}
void CustomElementReactionStack::invokeBackupQueue()
{
DCHECK(isMainThread());
invokeReactions(*m_backupQueue);
m_backupQueue->clear();
}
} // namespace blink