1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "config.h"
6#include "core/dom/custom/CustomElementMicrotaskDispatcher.h"
7
8#include "core/dom/Microtask.h"
9#include "core/dom/custom/CustomElementCallbackQueue.h"
10#include "core/dom/custom/CustomElementMicrotaskImportStep.h"
11#include "core/dom/custom/CustomElementProcessingStack.h"
12#include "core/dom/custom/CustomElementScheduler.h"
13#include "wtf/MainThread.h"
14
15namespace blink {
16
17static const CustomElementCallbackQueue::ElementQueueId kMicrotaskQueueId = 0;
18
19CustomElementMicrotaskDispatcher::CustomElementMicrotaskDispatcher()
20    : m_hasScheduledMicrotask(false)
21    , m_phase(Quiescent)
22{
23}
24
25DEFINE_EMPTY_DESTRUCTOR_WILL_BE_REMOVED(CustomElementMicrotaskDispatcher)
26
27CustomElementMicrotaskDispatcher& CustomElementMicrotaskDispatcher::instance()
28{
29    DEFINE_STATIC_LOCAL(OwnPtrWillBePersistent<CustomElementMicrotaskDispatcher>, instance, (adoptPtrWillBeNoop(new CustomElementMicrotaskDispatcher())));
30    return *instance;
31}
32
33void CustomElementMicrotaskDispatcher::enqueue(CustomElementCallbackQueue* queue)
34{
35    ensureMicrotaskScheduledForElementQueue();
36    queue->setOwner(kMicrotaskQueueId);
37    m_elements.append(queue);
38}
39
40void CustomElementMicrotaskDispatcher::ensureMicrotaskScheduledForElementQueue()
41{
42    ASSERT(m_phase == Quiescent || m_phase == Resolving);
43    ensureMicrotaskScheduled();
44}
45
46void CustomElementMicrotaskDispatcher::ensureMicrotaskScheduled()
47{
48    if (!m_hasScheduledMicrotask) {
49        Microtask::enqueueMicrotask(WTF::bind(&dispatch));
50        m_hasScheduledMicrotask = true;
51    }
52}
53
54void CustomElementMicrotaskDispatcher::dispatch()
55{
56    instance().doDispatch();
57}
58
59void CustomElementMicrotaskDispatcher::doDispatch()
60{
61    ASSERT(isMainThread());
62
63    ASSERT(m_phase == Quiescent && m_hasScheduledMicrotask);
64    m_hasScheduledMicrotask = false;
65
66    // Finishing microtask work deletes all
67    // CustomElementCallbackQueues. Being in a callback delivery scope
68    // implies those queues could still be in use.
69    ASSERT_WITH_SECURITY_IMPLICATION(!CustomElementProcessingStack::inCallbackDeliveryScope());
70
71    m_phase = Resolving;
72
73    m_phase = DispatchingCallbacks;
74    for (WillBeHeapVector<RawPtrWillBeMember<CustomElementCallbackQueue> >::iterator it = m_elements.begin(); it != m_elements.end(); ++it) {
75        // Created callback may enqueue an attached callback.
76        CustomElementProcessingStack::CallbackDeliveryScope scope;
77        (*it)->processInElementQueue(kMicrotaskQueueId);
78    }
79
80    m_elements.clear();
81    CustomElementScheduler::microtaskDispatcherDidFinish();
82    m_phase = Quiescent;
83}
84
85void CustomElementMicrotaskDispatcher::trace(Visitor* visitor)
86{
87#if ENABLE(OILPAN)
88    visitor->trace(m_elements);
89#endif
90}
91
92} // namespace blink
93