Home | History | Annotate | Download | only in imports
      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