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