blob: fc958b2496a6f236fb0d32c7c1dbaf00ca424b38 [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 "third_party/blink/renderer/core/html/custom/custom_element_reaction_stack.h"
#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/html/custom/ce_reactions_scope.h"
#include "third_party/blink/renderer/core/html/custom/custom_element_reaction_queue.h"
#include "third_party/blink/renderer/platform/bindings/microtask.h"
namespace blink {
namespace {
Persistent<CustomElementReactionStack>& GetCustomElementReactionStack() {
DEFINE_STATIC_LOCAL(Persistent<CustomElementReactionStack>,
custom_element_reaction_stack,
(new CustomElementReactionStack));
return custom_element_reaction_stack;
}
} // namespace
// TODO(dominicc): Consider using linked heap structures, avoiding
// finalizers, to make short-lived entries fast.
CustomElementReactionStack::CustomElementReactionStack() = default;
void CustomElementReactionStack::Trace(blink::Visitor* visitor) {
visitor->Trace(map_);
visitor->Trace(stack_);
visitor->Trace(backup_queue_);
}
void CustomElementReactionStack::TraceWrappers(
ScriptWrappableVisitor* visitor) const {
for (auto key : map_.Keys()) {
visitor->TraceWrappers(key);
}
}
void CustomElementReactionStack::Push() {
stack_.push_back(nullptr);
}
void CustomElementReactionStack::PopInvokingReactions() {
ElementQueue* queue = stack_.back();
if (queue)
InvokeReactions(*queue);
stack_.pop_back();
}
void CustomElementReactionStack::InvokeReactions(ElementQueue& queue) {
for (size_t i = 0; i < queue.size(); ++i) {
Element* element = queue[i];
if (CustomElementReactionQueue* reactions = map_.at(element)) {
reactions->InvokeReactions(element);
CHECK(reactions->IsEmpty());
map_.erase(element);
}
}
}
void CustomElementReactionStack::EnqueueToCurrentQueue(
Element* element,
CustomElementReaction* reaction) {
Enqueue(stack_.back(), element, reaction);
}
void CustomElementReactionStack::Enqueue(Member<ElementQueue>& queue,
Element* element,
CustomElementReaction* reaction) {
if (!queue)
queue = new ElementQueue();
queue->push_back(element);
CustomElementReactionQueue* reactions = map_.at(element);
if (!reactions) {
reactions = new CustomElementReactionQueue();
map_.insert(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(stack_.IsEmpty());
DCHECK(IsMainThread());
// If the processing the backup element queue is not set:
if (!backup_queue_ || backup_queue_->IsEmpty()) {
Microtask::EnqueueMicrotask(
WTF::Bind(&CustomElementReactionStack::InvokeBackupQueue,
Persistent<CustomElementReactionStack>(this)));
}
Enqueue(backup_queue_, element, reaction);
}
void CustomElementReactionStack::ClearQueue(Element* element) {
if (CustomElementReactionQueue* reactions = map_.at(element))
reactions->Clear();
}
void CustomElementReactionStack::InvokeBackupQueue() {
DCHECK(IsMainThread());
InvokeReactions(*backup_queue_);
backup_queue_->clear();
}
CustomElementReactionStack& CustomElementReactionStack::Current() {
return *GetCustomElementReactionStack();
}
CustomElementReactionStack*
CustomElementReactionStackTestSupport::SetCurrentForTest(
CustomElementReactionStack* new_stack) {
Persistent<CustomElementReactionStack>& stack =
GetCustomElementReactionStack();
CustomElementReactionStack* old_stack = stack.Get();
stack = new_stack;
return old_stack;
}
} // namespace blink