Home | History | Annotate | Download | only in shadow
      1 /*
      2  * Copyright (C) 2011 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  *     * Neither the name of Google Inc. nor the names of its
     11  * contributors may be used to endorse or promote products derived from
     12  * this software without specific prior written permission.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     15  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     16  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     17  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     18  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     19  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     20  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25  */
     26 
     27 #include "config.h"
     28 #include "core/dom/shadow/ShadowRoot.h"
     29 
     30 #include "bindings/core/v8/ExceptionState.h"
     31 #include "core/css/StyleSheetList.h"
     32 #include "core/css/resolver/StyleResolver.h"
     33 #include "core/css/resolver/StyleResolverParentScope.h"
     34 #include "core/dom/ElementTraversal.h"
     35 #include "core/dom/StyleEngine.h"
     36 #include "core/dom/Text.h"
     37 #include "core/dom/shadow/ElementShadow.h"
     38 #include "core/dom/shadow/InsertionPoint.h"
     39 #include "core/dom/shadow/ShadowRootRareData.h"
     40 #include "core/editing/markup.h"
     41 #include "core/html/HTMLShadowElement.h"
     42 #include "public/platform/Platform.h"
     43 
     44 namespace blink {
     45 
     46 struct SameSizeAsShadowRoot : public DocumentFragment, public TreeScope, public DoublyLinkedListNode<ShadowRoot> {
     47     void* pointers[3];
     48     unsigned countersAndFlags[1];
     49 };
     50 
     51 COMPILE_ASSERT(sizeof(ShadowRoot) == sizeof(SameSizeAsShadowRoot), shadowroot_should_stay_small);
     52 
     53 ShadowRoot::ShadowRoot(Document& document, ShadowRootType type)
     54     : DocumentFragment(0, CreateShadowRoot)
     55     , TreeScope(*this, document)
     56     , m_prev(nullptr)
     57     , m_next(nullptr)
     58     , m_numberOfStyles(0)
     59     , m_type(type)
     60     , m_registeredWithParentShadowRoot(false)
     61     , m_descendantInsertionPointsIsValid(false)
     62 {
     63 }
     64 
     65 ShadowRoot::~ShadowRoot()
     66 {
     67 #if !ENABLE(OILPAN)
     68     ASSERT(!m_prev);
     69     ASSERT(!m_next);
     70 
     71     if (m_shadowRootRareData && m_shadowRootRareData->styleSheets())
     72         m_shadowRootRareData->styleSheets()->detachFromDocument();
     73 
     74     document().styleEngine()->didRemoveShadowRoot(this);
     75 
     76     // We cannot let ContainerNode destructor call willBeDeletedFromDocument()
     77     // for this ShadowRoot instance because TreeScope destructor
     78     // clears Node::m_treeScope thus ContainerNode is no longer able
     79     // to access it Document reference after that.
     80     willBeDeletedFromDocument();
     81 
     82     // We must remove all of our children first before the TreeScope destructor
     83     // runs so we don't go through TreeScopeAdopter for each child with a
     84     // destructed tree scope in each descendant.
     85     removeDetachedChildren();
     86 
     87     // We must call clearRareData() here since a ShadowRoot class inherits TreeScope
     88     // as well as Node. See a comment on TreeScope.h for the reason.
     89     if (hasRareData())
     90         clearRareData();
     91 #endif
     92 }
     93 
     94 #if !ENABLE(OILPAN)
     95 void ShadowRoot::dispose()
     96 {
     97     removeDetachedChildren();
     98 }
     99 #endif
    100 
    101 ShadowRoot* ShadowRoot::olderShadowRootForBindings() const
    102 {
    103     ShadowRoot* older = olderShadowRoot();
    104     while (older && !older->shouldExposeToBindings())
    105         older = older->olderShadowRoot();
    106     ASSERT(!older || older->shouldExposeToBindings());
    107     return older;
    108 }
    109 
    110 PassRefPtrWillBeRawPtr<Node> ShadowRoot::cloneNode(bool, ExceptionState& exceptionState)
    111 {
    112     exceptionState.throwDOMException(DataCloneError, "ShadowRoot nodes are not clonable.");
    113     return nullptr;
    114 }
    115 
    116 String ShadowRoot::innerHTML() const
    117 {
    118     return createMarkup(this, ChildrenOnly);
    119 }
    120 
    121 void ShadowRoot::setInnerHTML(const String& markup, ExceptionState& exceptionState)
    122 {
    123     if (isOrphan()) {
    124         exceptionState.throwDOMException(InvalidAccessError, "The ShadowRoot does not have a host.");
    125         return;
    126     }
    127 
    128     if (RefPtrWillBeRawPtr<DocumentFragment> fragment = createFragmentForInnerOuterHTML(markup, host(), AllowScriptingContent, "innerHTML", exceptionState))
    129         replaceChildrenWithFragment(this, fragment.release(), exceptionState);
    130 }
    131 
    132 void ShadowRoot::recalcStyle(StyleRecalcChange change)
    133 {
    134     // ShadowRoot doesn't support custom callbacks.
    135     ASSERT(!hasCustomStyleCallbacks());
    136 
    137     StyleResolverParentScope parentScope(*this);
    138 
    139     if (styleChangeType() >= SubtreeStyleChange)
    140         change = Force;
    141 
    142     // There's no style to update so just calling recalcStyle means we're updated.
    143     clearNeedsStyleRecalc();
    144 
    145     recalcChildStyle(change);
    146     clearChildNeedsStyleRecalc();
    147 }
    148 
    149 void ShadowRoot::attach(const AttachContext& context)
    150 {
    151     StyleResolverParentScope parentScope(*this);
    152     DocumentFragment::attach(context);
    153 }
    154 
    155 Node::InsertionNotificationRequest ShadowRoot::insertedInto(ContainerNode* insertionPoint)
    156 {
    157     DocumentFragment::insertedInto(insertionPoint);
    158 
    159     if (!insertionPoint->inDocument() || !isOldest())
    160         return InsertionDone;
    161 
    162     // FIXME: When parsing <video controls>, insertedInto() is called many times without invoking removedFrom.
    163     // For now, we check m_registeredWithParentShadowroot. We would like to ASSERT(!m_registeredShadowRoot) here.
    164     // https://bugs.webkit.org/show_bug.cig?id=101316
    165     if (m_registeredWithParentShadowRoot)
    166         return InsertionDone;
    167 
    168     if (ShadowRoot* root = host()->containingShadowRoot()) {
    169         root->addChildShadowRoot();
    170         m_registeredWithParentShadowRoot = true;
    171     }
    172 
    173     return InsertionDone;
    174 }
    175 
    176 void ShadowRoot::removedFrom(ContainerNode* insertionPoint)
    177 {
    178     if (insertionPoint->inDocument() && m_registeredWithParentShadowRoot) {
    179         ShadowRoot* root = host()->containingShadowRoot();
    180         if (!root)
    181             root = insertionPoint->containingShadowRoot();
    182         if (root)
    183             root->removeChildShadowRoot();
    184         m_registeredWithParentShadowRoot = false;
    185     }
    186 
    187     DocumentFragment::removedFrom(insertionPoint);
    188 }
    189 
    190 void ShadowRoot::childrenChanged(const ChildrenChange& change)
    191 {
    192     ContainerNode::childrenChanged(change);
    193 
    194     if (change.isChildElementChange())
    195         checkForSiblingStyleChanges(change.type == ElementRemoved ? SiblingElementRemoved : SiblingElementInserted, change.siblingBeforeChange, change.siblingAfterChange);
    196 
    197     if (InsertionPoint* point = shadowInsertionPointOfYoungerShadowRoot()) {
    198         if (ShadowRoot* root = point->containingShadowRoot())
    199             root->owner()->setNeedsDistributionRecalc();
    200     }
    201 }
    202 
    203 void ShadowRoot::registerScopedHTMLStyleChild()
    204 {
    205     ++m_numberOfStyles;
    206 }
    207 
    208 void ShadowRoot::unregisterScopedHTMLStyleChild()
    209 {
    210     ASSERT(m_numberOfStyles > 0);
    211     --m_numberOfStyles;
    212 }
    213 
    214 ShadowRootRareData* ShadowRoot::ensureShadowRootRareData()
    215 {
    216     if (m_shadowRootRareData)
    217         return m_shadowRootRareData.get();
    218 
    219     m_shadowRootRareData = adoptPtrWillBeNoop(new ShadowRootRareData);
    220     return m_shadowRootRareData.get();
    221 }
    222 
    223 bool ShadowRoot::containsShadowElements() const
    224 {
    225     return m_shadowRootRareData ? m_shadowRootRareData->containsShadowElements() : 0;
    226 }
    227 
    228 bool ShadowRoot::containsContentElements() const
    229 {
    230     return m_shadowRootRareData ? m_shadowRootRareData->containsContentElements() : 0;
    231 }
    232 
    233 bool ShadowRoot::containsShadowRoots() const
    234 {
    235     return m_shadowRootRareData ? m_shadowRootRareData->containsShadowRoots() : 0;
    236 }
    237 
    238 unsigned ShadowRoot::descendantShadowElementCount() const
    239 {
    240     return m_shadowRootRareData ? m_shadowRootRareData->descendantShadowElementCount() : 0;
    241 }
    242 
    243 HTMLShadowElement* ShadowRoot::shadowInsertionPointOfYoungerShadowRoot() const
    244 {
    245     return m_shadowRootRareData ? m_shadowRootRareData->shadowInsertionPointOfYoungerShadowRoot() : 0;
    246 }
    247 
    248 void ShadowRoot::setShadowInsertionPointOfYoungerShadowRoot(PassRefPtrWillBeRawPtr<HTMLShadowElement> shadowInsertionPoint)
    249 {
    250     if (!m_shadowRootRareData && !shadowInsertionPoint)
    251         return;
    252     ensureShadowRootRareData()->setShadowInsertionPointOfYoungerShadowRoot(shadowInsertionPoint);
    253 }
    254 
    255 void ShadowRoot::didAddInsertionPoint(InsertionPoint* insertionPoint)
    256 {
    257     ensureShadowRootRareData()->didAddInsertionPoint(insertionPoint);
    258     invalidateDescendantInsertionPoints();
    259 }
    260 
    261 void ShadowRoot::didRemoveInsertionPoint(InsertionPoint* insertionPoint)
    262 {
    263     m_shadowRootRareData->didRemoveInsertionPoint(insertionPoint);
    264     invalidateDescendantInsertionPoints();
    265 }
    266 
    267 void ShadowRoot::addChildShadowRoot()
    268 {
    269     ensureShadowRootRareData()->didAddChildShadowRoot();
    270 }
    271 
    272 void ShadowRoot::removeChildShadowRoot()
    273 {
    274     // FIXME: Why isn't this an ASSERT?
    275     if (!m_shadowRootRareData)
    276         return;
    277     m_shadowRootRareData->didRemoveChildShadowRoot();
    278 }
    279 
    280 unsigned ShadowRoot::childShadowRootCount() const
    281 {
    282     return m_shadowRootRareData ? m_shadowRootRareData->childShadowRootCount() : 0;
    283 }
    284 
    285 void ShadowRoot::invalidateDescendantInsertionPoints()
    286 {
    287     m_descendantInsertionPointsIsValid = false;
    288     m_shadowRootRareData->clearDescendantInsertionPoints();
    289 }
    290 
    291 const WillBeHeapVector<RefPtrWillBeMember<InsertionPoint> >& ShadowRoot::descendantInsertionPoints()
    292 {
    293     DEFINE_STATIC_LOCAL(WillBePersistentHeapVector<RefPtrWillBeMember<InsertionPoint> >, emptyList, ());
    294     if (m_shadowRootRareData && m_descendantInsertionPointsIsValid)
    295         return m_shadowRootRareData->descendantInsertionPoints();
    296 
    297     m_descendantInsertionPointsIsValid = true;
    298 
    299     if (!containsInsertionPoints())
    300         return emptyList;
    301 
    302     WillBeHeapVector<RefPtrWillBeMember<InsertionPoint> > insertionPoints;
    303     for (InsertionPoint* insertionPoint = Traversal<InsertionPoint>::firstWithin(*this); insertionPoint; insertionPoint = Traversal<InsertionPoint>::next(*insertionPoint, this))
    304         insertionPoints.append(insertionPoint);
    305 
    306     ensureShadowRootRareData()->setDescendantInsertionPoints(insertionPoints);
    307 
    308     return m_shadowRootRareData->descendantInsertionPoints();
    309 }
    310 
    311 StyleSheetList* ShadowRoot::styleSheets()
    312 {
    313     if (!ensureShadowRootRareData()->styleSheets())
    314         m_shadowRootRareData->setStyleSheets(StyleSheetList::create(this));
    315 
    316     return m_shadowRootRareData->styleSheets();
    317 }
    318 
    319 void ShadowRoot::trace(Visitor* visitor)
    320 {
    321     visitor->trace(m_prev);
    322     visitor->trace(m_next);
    323     visitor->trace(m_shadowRootRareData);
    324     TreeScope::trace(visitor);
    325     DocumentFragment::trace(visitor);
    326 }
    327 
    328 }
    329