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 20 CustomElementMicrotaskDispatcher::CustomElementMicrotaskDispatcher() 21 : m_hasScheduledMicrotask(false) 22 , m_phase(Quiescent) 23 , m_steps(CustomElementMicrotaskStepDispatcher::create()) 24 { 25 } 26 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 35 void CustomElementMicrotaskDispatcher::enqueue(HTMLImportLoader* parentLoader, PassOwnPtrWillBeRawPtr<CustomElementMicrotaskStep> step) 36 { 37 ensureMicrotaskScheduledForMicrotaskSteps(); 38 m_steps->enqueue(parentLoader, step); 39 } 40 41 void CustomElementMicrotaskDispatcher::enqueue(HTMLImportLoader* parentLoader, PassOwnPtrWillBeRawPtr<CustomElementMicrotaskImportStep> step, bool importIsSync) 42 { 43 ensureMicrotaskScheduledForMicrotaskSteps(); 44 m_steps->enqueue(parentLoader, step, importIsSync); 45 } 46 47 void CustomElementMicrotaskDispatcher::enqueue(CustomElementCallbackQueue* queue) 48 { 49 ensureMicrotaskScheduledForElementQueue(); 50 queue->setOwner(kMicrotaskQueueId); 51 m_elements.append(queue); 52 } 53 54 void CustomElementMicrotaskDispatcher::importDidFinish(CustomElementMicrotaskImportStep* step) 55 { 56 ensureMicrotaskScheduledForMicrotaskSteps(); 57 } 58 59 void CustomElementMicrotaskDispatcher::ensureMicrotaskScheduledForMicrotaskSteps() 60 { 61 ASSERT(m_phase == Quiescent || m_phase == DispatchingCallbacks); 62 ensureMicrotaskScheduled(); 63 } 64 65 void CustomElementMicrotaskDispatcher::ensureMicrotaskScheduledForElementQueue() 66 { 67 ASSERT(m_phase == Quiescent || m_phase == Resolving); 68 ensureMicrotaskScheduled(); 69 } 70 71 void CustomElementMicrotaskDispatcher::ensureMicrotaskScheduled() 72 { 73 if (!m_hasScheduledMicrotask) { 74 Microtask::enqueueMicrotask(WTF::bind(&dispatch)); 75 m_hasScheduledMicrotask = true; 76 } 77 } 78 79 void CustomElementMicrotaskDispatcher::dispatch() 80 { 81 instance().doDispatch(); 82 } 83 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 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) 120 void CustomElementMicrotaskDispatcher::show() 121 { 122 m_steps->show(2); 123 124 } 125 #endif 126 127 } // namespace WebCore 128 129 #if !defined(NDEBUG) 130 void showCEMD() 131 { 132 WebCore::CustomElementMicrotaskDispatcher::instance().show(); 133 } 134 #endif 135