Commit df342034 authored by Dominic Cooney's avatar Dominic Cooney

Add a queue for custom element reactions.

https://html.spec.whatwg.org/multipage/scripting.html#custom-element-reaction-queue

BUG=594918
R=kojii@chromium.org

Review URL: https://codereview.chromium.org/2021763002 .

Cr-Commit-Position: refs/heads/master@{#396790}
parent 090145cb
......@@ -2634,10 +2634,13 @@
'dom/custom/CustomElementDefinition.cpp',
'dom/custom/CustomElementDefinition.h',
'dom/custom/CustomElementDefinitionBuilder.h',
'dom/custom/CustomElementUpgradeSorter.cpp',
'dom/custom/CustomElementUpgradeSorter.h',
'dom/custom/CustomElementDescriptor.h',
'dom/custom/CustomElementDescriptorHash.h',
'dom/custom/CustomElementReaction.h',
'dom/custom/CustomElementReactionQueue.cpp',
'dom/custom/CustomElementReactionQueue.h',
'dom/custom/CustomElementUpgradeSorter.cpp',
'dom/custom/CustomElementUpgradeSorter.h',
'dom/custom/CustomElementsRegistry.cpp',
'dom/custom/CustomElementsRegistry.h',
'dom/custom/V0CustomElement.cpp',
......@@ -3984,6 +3987,7 @@
'dom/URLSearchParamsTest.cpp',
'dom/custom/CustomElementTest.cpp',
'dom/custom/CustomElementDescriptorTest.cpp',
'dom/custom/CustomElementReactionQueueTest.cpp',
'dom/custom/CustomElementUpgradeSorterTest.cpp',
'dom/shadow/FlatTreeTraversalTest.cpp',
'editing/EditingCommandTest.cpp',
......
// 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.
#ifndef CustomElementReaction_h
#define CustomElementReaction_h
#include "core/CoreExport.h"
#include "platform/heap/Handle.h"
#include "wtf/Noncopyable.h"
namespace blink {
class Element;
class CORE_EXPORT CustomElementReaction
: public GarbageCollectedFinalized<CustomElementReaction> {
WTF_MAKE_NONCOPYABLE(CustomElementReaction);
public:
CustomElementReaction() { }
virtual ~CustomElementReaction() { }
DEFINE_INLINE_VIRTUAL_TRACE() { }
virtual void invoke(Element*) = 0;
};
} // namespace blink
#endif // CustomElementReaction_h
// 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/CustomElementReactionQueue.h"
#include "core/dom/custom/CustomElementReaction.h"
namespace blink {
CustomElementReactionQueue::CustomElementReactionQueue()
: m_index(0u)
{
}
CustomElementReactionQueue::~CustomElementReactionQueue()
{
}
DEFINE_TRACE(CustomElementReactionQueue)
{
visitor->trace(m_reactions);
}
void CustomElementReactionQueue::add(CustomElementReaction* reaction)
{
m_reactions.append(reaction);
}
// There is one queue per element, so this could be invoked
// recursively.
void CustomElementReactionQueue::invokeReactions(Element* element)
{
while (m_index < m_reactions.size()) {
CustomElementReaction* reaction = m_reactions[m_index];
m_reactions[m_index++] = nullptr;
reaction->invoke(element);
}
// Unlike V0CustomElementsCallbackQueue, reactions are always
// inserted by steps which bump the global element queue. This
// means we do not need queue "owner" guards.
// https://html.spec.whatwg.org/multipage/scripting.html#custom-element-reactions
m_index = 0;
m_reactions.resize(0);
}
} // namespace blink
// 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.
#ifndef CustomElementReactionQueue_h
#define CustomElementReactionQueue_h
#include "core/CoreExport.h"
#include "platform/heap/Handle.h"
#include "wtf/Noncopyable.h"
namespace blink {
class CustomElementReaction;
class Element;
class CORE_EXPORT CustomElementReactionQueue final
: public GarbageCollectedFinalized<CustomElementReactionQueue> {
WTF_MAKE_NONCOPYABLE(CustomElementReactionQueue);
public:
CustomElementReactionQueue();
~CustomElementReactionQueue();
DECLARE_TRACE();
void add(CustomElementReaction*);
void invokeReactions(Element*);
private:
HeapVector<Member<CustomElementReaction>> m_reactions;
size_t m_index;
};
} // namespace blink
#endif // CustomElementReactionQueue_h
// 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/CustomElementReactionQueue.h"
#include "core/dom/custom/CustomElementReaction.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "wtf/text/AtomicString.h"
#include <initializer_list>
#include <vector>
namespace blink {
class Command : public GarbageCollectedFinalized<Command> {
WTF_MAKE_NONCOPYABLE(Command);
public:
Command() { }
virtual ~Command() { }
DEFINE_INLINE_VIRTUAL_TRACE() { }
virtual void run(Element*) = 0;
};
class Log : public Command {
WTF_MAKE_NONCOPYABLE(Log);
public:
Log(char what, std::vector<char>& where) : m_what(what), m_where(where) { }
virtual ~Log() { }
void run(Element*) override { m_where.push_back(m_what); }
private:
char m_what;
std::vector<char>& m_where;
};
class Recurse : public Command {
WTF_MAKE_NONCOPYABLE(Recurse);
public:
Recurse(CustomElementReactionQueue* queue) : m_queue(queue) { }
virtual ~Recurse() { }
DEFINE_INLINE_VIRTUAL_TRACE()
{
Command::trace(visitor);
visitor->trace(m_queue);
}
void run(Element* element) override { m_queue->invokeReactions(element); }
private:
Member<CustomElementReactionQueue> m_queue;
};
class Enqueue : public Command {
WTF_MAKE_NONCOPYABLE(Enqueue);
public:
Enqueue(CustomElementReactionQueue* queue, CustomElementReaction* reaction)
: m_queue(queue)
, m_reaction(reaction)
{
}
virtual ~Enqueue() { }
DEFINE_INLINE_VIRTUAL_TRACE()
{
Command::trace(visitor);
visitor->trace(m_queue);
visitor->trace(m_reaction);
}
void run(Element*) override
{
m_queue->add(m_reaction);
}
private:
Member<CustomElementReactionQueue> m_queue;
Member<CustomElementReaction> m_reaction;
};
class TestReaction : public CustomElementReaction {
WTF_MAKE_NONCOPYABLE(TestReaction);
public:
TestReaction(std::initializer_list<Command*> commands)
{
// TODO(dominicc): Simply pass the initializer list when
// HeapVector supports initializer lists like Vector.
for (auto& command : commands)
m_commands.append(command);
}
virtual ~TestReaction() = default;
DEFINE_INLINE_VIRTUAL_TRACE()
{
CustomElementReaction::trace(visitor);
visitor->trace(m_commands);
}
void invoke(Element* element) override
{
for (auto& command : m_commands)
command->run(element);
}
private:
HeapVector<Member<Command>> m_commands;
};
TEST(CustomElementReactionQueueTest, invokeReactions_one)
{
std::vector<char> log;
CustomElementReactionQueue* queue = new CustomElementReactionQueue();
queue->add(new TestReaction({new Log('a', log)}));
queue->invokeReactions(nullptr);
EXPECT_EQ(log, std::vector<char>({'a'}))
<< "the reaction should have been invoked";
}
TEST(CustomElementReactionQueueTest, invokeReactions_many)
{
std::vector<char> log;
CustomElementReactionQueue* queue = new CustomElementReactionQueue();
queue->add(new TestReaction({new Log('a', log)}));
queue->add(new TestReaction({new Log('b', log)}));
queue->add(new TestReaction({new Log('c', log)}));
queue->invokeReactions(nullptr);
EXPECT_EQ(log, std::vector<char>({'a', 'b', 'c'}))
<< "the reaction should have been invoked";
}
TEST(CustomElementReactionQueueTest, invokeReactions_recursive)
{
std::vector<char> log;
CustomElementReactionQueue* queue = new CustomElementReactionQueue();
CustomElementReaction* third = new TestReaction({
new Log('c', log),
new Recurse(queue)}); // "Empty" recursion
CustomElementReaction* second = new TestReaction({
new Log('b', log),
new Enqueue(queue, third)}); // Unwinds one level of recursion
CustomElementReaction* first = new TestReaction({
new Log('a', log),
new Enqueue(queue, second),
new Recurse(queue)}); // Non-empty recursion
queue->add(first);
queue->invokeReactions(nullptr);
EXPECT_EQ(log, std::vector<char>({'a', 'b', 'c'}))
<< "the reactions should have been invoked";
}
} // namespace blink
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment