1 /* 2 * Copyright (C) 2013 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "config.h" 32 #include "core/html/imports/HTMLImportChild.h" 33 34 #include "core/dom/Document.h" 35 #include "core/dom/custom/CustomElement.h" 36 #include "core/dom/custom/CustomElementMicrotaskDispatcher.h" 37 #include "core/dom/custom/CustomElementMicrotaskImportStep.h" 38 #include "core/dom/custom/CustomElementSyncMicrotaskQueue.h" 39 #include "core/html/imports/HTMLImportChildClient.h" 40 #include "core/html/imports/HTMLImportLoader.h" 41 #include "core/html/imports/HTMLImportTreeRoot.h" 42 #include "core/html/imports/HTMLImportsController.h" 43 44 namespace WebCore { 45 46 HTMLImportChild::HTMLImportChild(const KURL& url, HTMLImportLoader* loader, SyncMode sync) 47 : HTMLImport(sync) 48 , m_url(url) 49 #if !ENABLE(OILPAN) 50 , m_weakFactory(this) 51 #endif 52 , m_loader(loader) 53 , m_client(nullptr) 54 { 55 } 56 57 HTMLImportChild::~HTMLImportChild() 58 { 59 #if !ENABLE(OILPAN) 60 // importDestroyed() should be called before the destruction. 61 ASSERT(!m_loader); 62 63 if (m_client) 64 m_client->importChildWasDestroyed(this); 65 #endif 66 } 67 68 void HTMLImportChild::ownerInserted() 69 { 70 if (!m_loader->isDone()) 71 return; 72 root()->document()->styleResolverChanged(); 73 } 74 75 void HTMLImportChild::didShareLoader() 76 { 77 createCustomElementMicrotaskStepIfNeeded(); 78 stateWillChange(); 79 } 80 81 void HTMLImportChild::didStartLoading() 82 { 83 createCustomElementMicrotaskStepIfNeeded(); 84 } 85 86 void HTMLImportChild::didFinish() 87 { 88 if (m_client) 89 m_client->didFinish(); 90 } 91 92 void HTMLImportChild::didFinishLoading() 93 { 94 stateWillChange(); 95 if (m_customElementMicrotaskStep) 96 CustomElementMicrotaskDispatcher::instance().importDidFinish(m_customElementMicrotaskStep.get()); 97 } 98 99 void HTMLImportChild::didFinishUpgradingCustomElements() 100 { 101 stateWillChange(); 102 m_customElementMicrotaskStep.clear(); 103 } 104 105 #if !ENABLE(OILPAN) 106 void HTMLImportChild::importDestroyed() 107 { 108 if (parent()) 109 parent()->removeChild(this); 110 111 ASSERT(m_loader); 112 m_loader->removeImport(this); 113 m_loader = nullptr; 114 } 115 #endif 116 117 Document* HTMLImportChild::document() const 118 { 119 ASSERT(m_loader); 120 return m_loader->document(); 121 } 122 123 void HTMLImportChild::stateWillChange() 124 { 125 toHTMLImportTreeRoot(root())->scheduleRecalcState(); 126 } 127 128 void HTMLImportChild::stateDidChange() 129 { 130 HTMLImport::stateDidChange(); 131 132 if (state().isReady()) 133 didFinish(); 134 } 135 136 void HTMLImportChild::createCustomElementMicrotaskStepIfNeeded() 137 { 138 // HTMLImportChild::normalize(), which is called from HTMLImportLoader::addImport(), 139 // can move import children to new parents. So their microtask steps should be updated as well, 140 // to let the steps be in the new parent queues.This method handles such migration. 141 // For implementation simplicity, outdated step objects that are owned by moved children 142 // aren't removed from the (now wrong) queues. Instead, each step invalidates its content so that 143 // it is removed from the wrong queue during the next traversal. See parentWasChanged() for the detail. 144 145 if (m_customElementMicrotaskStep) { 146 m_customElementMicrotaskStep->parentWasChanged(); 147 m_customElementMicrotaskStep.clear(); 148 } 149 150 if (!isDone() && !formsCycle()) { 151 #if ENABLE(OILPAN) 152 m_customElementMicrotaskStep = CustomElement::didCreateImport(this); 153 #else 154 m_customElementMicrotaskStep = CustomElement::didCreateImport(this)->weakPtr(); 155 #endif 156 } 157 158 for (HTMLImport* child = firstChild(); child; child = child->next()) 159 toHTMLImportChild(child)->createCustomElementMicrotaskStepIfNeeded(); 160 } 161 162 bool HTMLImportChild::isDone() const 163 { 164 ASSERT(m_loader); 165 166 return m_loader->isDone() && m_loader->microtaskQueue()->isEmpty() && !m_customElementMicrotaskStep; 167 } 168 169 HTMLImportLoader* HTMLImportChild::loader() const 170 { 171 // This should never be called after importDestroyed. 172 ASSERT(m_loader); 173 return m_loader; 174 } 175 176 void HTMLImportChild::setClient(HTMLImportChildClient* client) 177 { 178 ASSERT(client); 179 ASSERT(!m_client); 180 m_client = client; 181 } 182 183 #if !ENABLE(OILPAN) 184 void HTMLImportChild::clearClient() 185 { 186 // Doesn't check m_client nullity because we allow 187 // clearClient() to reenter. 188 m_client = nullptr; 189 } 190 #endif 191 192 HTMLLinkElement* HTMLImportChild::link() const 193 { 194 if (!m_client) 195 return 0; 196 return m_client->link(); 197 } 198 199 // Ensuring following invariants against the import tree: 200 // - HTMLImportChild::firstImport() is the "first import" of the DFS order of the import tree. 201 // - The "first import" manages all the children that is loaded by the document. 202 void HTMLImportChild::normalize() 203 { 204 if (!loader()->isFirstImport(this) && this->precedes(loader()->firstImport())) { 205 HTMLImportChild* oldFirst = loader()->firstImport(); 206 loader()->moveToFirst(this); 207 takeChildrenFrom(oldFirst); 208 } 209 210 for (HTMLImport* child = firstChild(); child; child = child->next()) 211 toHTMLImportChild(child)->normalize(); 212 } 213 214 #if !defined(NDEBUG) 215 void HTMLImportChild::showThis() 216 { 217 bool isFirst = loader() ? loader()->isFirstImport(this) : false; 218 HTMLImport::showThis(); 219 fprintf(stderr, " loader=%p first=%d, step=%p sync=%s url=%s", 220 m_loader.get(), 221 isFirst, 222 m_customElementMicrotaskStep.get(), 223 isSync() ? "Y" : "N", 224 url().string().utf8().data()); 225 } 226 #endif 227 228 void HTMLImportChild::trace(Visitor* visitor) 229 { 230 visitor->trace(m_customElementMicrotaskStep); 231 visitor->trace(m_loader); 232 visitor->trace(m_client); 233 HTMLImport::trace(visitor); 234 } 235 236 } // namespace WebCore 237