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/CustomElementMicrotaskImportStep.h" 37 #include "core/dom/custom/CustomElementSyncMicrotaskQueue.h" 38 #include "core/html/imports/HTMLImportChildClient.h" 39 #include "core/html/imports/HTMLImportLoader.h" 40 #include "core/html/imports/HTMLImportTreeRoot.h" 41 #include "core/html/imports/HTMLImportsController.h" 42 43 namespace blink { 44 45 HTMLImportChild::HTMLImportChild(const KURL& url, HTMLImportLoader* loader, SyncMode sync) 46 : HTMLImport(sync) 47 , m_url(url) 48 #if !ENABLE(OILPAN) 49 , m_weakFactory(this) 50 #endif 51 , m_loader(loader) 52 , m_client(nullptr) 53 { 54 } 55 56 HTMLImportChild::~HTMLImportChild() 57 { 58 #if !ENABLE(OILPAN) 59 // importDestroyed() should be called before the destruction. 60 ASSERT(!m_loader); 61 62 if (m_client) 63 m_client->importChildWasDestroyed(this); 64 #endif 65 } 66 67 void HTMLImportChild::ownerInserted() 68 { 69 if (!m_loader->isDone()) 70 return; 71 root()->document()->styleResolverChanged(); 72 } 73 74 void HTMLImportChild::didShareLoader() 75 { 76 createCustomElementMicrotaskStepIfNeeded(); 77 stateWillChange(); 78 } 79 80 void HTMLImportChild::didStartLoading() 81 { 82 createCustomElementMicrotaskStepIfNeeded(); 83 } 84 85 void HTMLImportChild::didFinish() 86 { 87 if (m_client) 88 m_client->didFinish(); 89 } 90 91 void HTMLImportChild::didFinishLoading() 92 { 93 stateWillChange(); 94 CustomElement::didFinishLoadingImport(*(root()->document())); 95 } 96 97 void HTMLImportChild::didFinishUpgradingCustomElements() 98 { 99 stateWillChange(); 100 m_customElementMicrotaskStep.clear(); 101 } 102 103 #if !ENABLE(OILPAN) 104 void HTMLImportChild::importDestroyed() 105 { 106 if (parent()) 107 parent()->removeChild(this); 108 109 ASSERT(m_loader); 110 m_loader->removeImport(this); 111 m_loader = nullptr; 112 } 113 #endif 114 115 Document* HTMLImportChild::document() const 116 { 117 ASSERT(m_loader); 118 return m_loader->document(); 119 } 120 121 void HTMLImportChild::stateWillChange() 122 { 123 toHTMLImportTreeRoot(root())->scheduleRecalcState(); 124 } 125 126 void HTMLImportChild::stateDidChange() 127 { 128 HTMLImport::stateDidChange(); 129 130 if (state().isReady()) 131 didFinish(); 132 } 133 134 void HTMLImportChild::invalidateCustomElementMicrotaskStep() 135 { 136 if (!m_customElementMicrotaskStep) 137 return; 138 m_customElementMicrotaskStep->invalidate(); 139 m_customElementMicrotaskStep.clear(); 140 } 141 142 void HTMLImportChild::createCustomElementMicrotaskStepIfNeeded() 143 { 144 ASSERT(!m_customElementMicrotaskStep); 145 146 if (!isDone() && !formsCycle()) { 147 #if ENABLE(OILPAN) 148 m_customElementMicrotaskStep = CustomElement::didCreateImport(this); 149 #else 150 m_customElementMicrotaskStep = CustomElement::didCreateImport(this)->weakPtr(); 151 #endif 152 } 153 } 154 155 bool HTMLImportChild::isDone() const 156 { 157 ASSERT(m_loader); 158 159 return m_loader->isDone() && m_loader->microtaskQueue()->isEmpty() && !m_customElementMicrotaskStep; 160 } 161 162 HTMLImportLoader* HTMLImportChild::loader() const 163 { 164 // This should never be called after importDestroyed. 165 ASSERT(m_loader); 166 return m_loader; 167 } 168 169 void HTMLImportChild::setClient(HTMLImportChildClient* client) 170 { 171 ASSERT(client); 172 ASSERT(!m_client); 173 m_client = client; 174 } 175 176 #if !ENABLE(OILPAN) 177 void HTMLImportChild::clearClient() 178 { 179 // Doesn't check m_client nullity because we allow 180 // clearClient() to reenter. 181 m_client = nullptr; 182 } 183 #endif 184 185 HTMLLinkElement* HTMLImportChild::link() const 186 { 187 if (!m_client) 188 return 0; 189 return m_client->link(); 190 } 191 192 // Ensuring following invariants against the import tree: 193 // - HTMLImportChild::firstImport() is the "first import" of the DFS order of the import tree. 194 // - The "first import" manages all the children that is loaded by the document. 195 void HTMLImportChild::normalize() 196 { 197 if (!loader()->isFirstImport(this) && this->precedes(loader()->firstImport())) { 198 HTMLImportChild* oldFirst = loader()->firstImport(); 199 loader()->moveToFirst(this); 200 takeChildrenFrom(oldFirst); 201 } 202 203 for (HTMLImportChild* child = toHTMLImportChild(firstChild()); child; child = toHTMLImportChild(child->next())) { 204 if (child->formsCycle()) 205 child->invalidateCustomElementMicrotaskStep(); 206 child->normalize(); 207 } 208 } 209 210 #if !defined(NDEBUG) 211 void HTMLImportChild::showThis() 212 { 213 bool isFirst = loader() ? loader()->isFirstImport(this) : false; 214 HTMLImport::showThis(); 215 fprintf(stderr, " loader=%p first=%d, step=%p sync=%s url=%s", 216 m_loader.get(), 217 isFirst, 218 m_customElementMicrotaskStep.get(), 219 isSync() ? "Y" : "N", 220 url().string().utf8().data()); 221 } 222 #endif 223 224 void HTMLImportChild::trace(Visitor* visitor) 225 { 226 visitor->trace(m_customElementMicrotaskStep); 227 visitor->trace(m_loader); 228 visitor->trace(m_client); 229 HTMLImport::trace(visitor); 230 } 231 232 } // namespace blink 233