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/CustomElementCallbackDispatcher.h"
10 #include "core/dom/custom/CustomElementCallbackQueue.h"
11 #include "core/dom/custom/CustomElementMicrotaskImportStep.h"
12 #include "core/dom/custom/CustomElementMicrotaskStepDispatcher.h"
13 #include "core/dom/custom/CustomElementScheduler.h"
14 #include "wtf/MainThread.h"
15
16 namespace WebCore {
17
18 static const CustomElementCallbackQueue::ElementQueueId kMicrotaskQueueId = 0;
19
CustomElementMicrotaskDispatcher()20 CustomElementMicrotaskDispatcher::CustomElementMicrotaskDispatcher()
21 : m_hasScheduledMicrotask(false)
22 , m_phase(Quiescent)
23 , m_steps(CustomElementMicrotaskStepDispatcher::create())
24 {
25 }
26
DEFINE_EMPTY_DESTRUCTOR_WILL_BE_REMOVED(CustomElementMicrotaskDispatcher)27 DEFINE_EMPTY_DESTRUCTOR_WILL_BE_REMOVED(CustomElementMicrotaskDispatcher)
28
29 CustomElementMicrotaskDispatcher& CustomElementMicrotaskDispatcher::instance()
30 {
31 DEFINE_STATIC_LOCAL(OwnPtrWillBePersistent<CustomElementMicrotaskDispatcher>, instance, (adoptPtrWillBeNoop(new CustomElementMicrotaskDispatcher())));
32 return *instance;
33 }
34
enqueue(HTMLImportLoader * parentLoader,PassOwnPtrWillBeRawPtr<CustomElementMicrotaskStep> step)35 void CustomElementMicrotaskDispatcher::enqueue(HTMLImportLoader* parentLoader, PassOwnPtrWillBeRawPtr<CustomElementMicrotaskStep> step)
36 {
37 ensureMicrotaskScheduledForMicrotaskSteps();
38 m_steps->enqueue(parentLoader, step);
39 }
40
enqueue(HTMLImportLoader * parentLoader,PassOwnPtrWillBeRawPtr<CustomElementMicrotaskImportStep> step,bool importIsSync)41 void CustomElementMicrotaskDispatcher::enqueue(HTMLImportLoader* parentLoader, PassOwnPtrWillBeRawPtr<CustomElementMicrotaskImportStep> step, bool importIsSync)
42 {
43 ensureMicrotaskScheduledForMicrotaskSteps();
44 m_steps->enqueue(parentLoader, step, importIsSync);
45 }
46
enqueue(CustomElementCallbackQueue * queue)47 void CustomElementMicrotaskDispatcher::enqueue(CustomElementCallbackQueue* queue)
48 {
49 ensureMicrotaskScheduledForElementQueue();
50 queue->setOwner(kMicrotaskQueueId);
51 m_elements.append(queue);
52 }
53
importDidFinish(CustomElementMicrotaskImportStep * step)54 void CustomElementMicrotaskDispatcher::importDidFinish(CustomElementMicrotaskImportStep* step)
55 {
56 ensureMicrotaskScheduledForMicrotaskSteps();
57 }
58
ensureMicrotaskScheduledForMicrotaskSteps()59 void CustomElementMicrotaskDispatcher::ensureMicrotaskScheduledForMicrotaskSteps()
60 {
61 ASSERT(m_phase == Quiescent || m_phase == DispatchingCallbacks);
62 ensureMicrotaskScheduled();
63 }
64
ensureMicrotaskScheduledForElementQueue()65 void CustomElementMicrotaskDispatcher::ensureMicrotaskScheduledForElementQueue()
66 {
67 ASSERT(m_phase == Quiescent || m_phase == Resolving);
68 ensureMicrotaskScheduled();
69 }
70
ensureMicrotaskScheduled()71 void CustomElementMicrotaskDispatcher::ensureMicrotaskScheduled()
72 {
73 if (!m_hasScheduledMicrotask) {
74 Microtask::enqueueMicrotask(WTF::bind(&dispatch));
75 m_hasScheduledMicrotask = true;
76 }
77 }
78
dispatch()79 void CustomElementMicrotaskDispatcher::dispatch()
80 {
81 instance().doDispatch();
82 }
83
doDispatch()84 void CustomElementMicrotaskDispatcher::doDispatch()
85 {
86 ASSERT(isMainThread());
87
88 ASSERT(m_phase == Quiescent && m_hasScheduledMicrotask);
89 m_hasScheduledMicrotask = false;
90
91 // Finishing microtask work deletes all
92 // CustomElementCallbackQueues. Being in a callback delivery scope
93 // implies those queues could still be in use.
94 ASSERT_WITH_SECURITY_IMPLICATION(!CustomElementCallbackDispatcher::inCallbackDeliveryScope());
95
96 m_phase = Resolving;
97 m_steps->dispatch();
98
99 m_phase = DispatchingCallbacks;
100 for (WillBeHeapVector<RawPtrWillBeMember<CustomElementCallbackQueue> >::iterator it = m_elements.begin(); it != m_elements.end(); ++it) {
101 // Created callback may enqueue an attached callback.
102 CustomElementCallbackDispatcher::CallbackDeliveryScope scope;
103 (*it)->processInElementQueue(kMicrotaskQueueId);
104 }
105
106 m_elements.clear();
107 CustomElementScheduler::microtaskDispatcherDidFinish();
108 m_phase = Quiescent;
109 }
110
trace(Visitor * visitor)111 void CustomElementMicrotaskDispatcher::trace(Visitor* visitor)
112 {
113 visitor->trace(m_steps);
114 #if ENABLE(OILPAN)
115 visitor->trace(m_elements);
116 #endif
117 }
118
119 #if !defined(NDEBUG)
show()120 void CustomElementMicrotaskDispatcher::show()
121 {
122 m_steps->show(2);
123
124 }
125 #endif
126
127 } // namespace WebCore
128
129 #if !defined(NDEBUG)
showCEMD()130 void showCEMD()
131 {
132 WebCore::CustomElementMicrotaskDispatcher::instance().show();
133 }
134 #endif
135