1 /* 2 * Copyright (C) 2012 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/dom/shadow/InsertionPoint.h" 33 34 #include "HTMLNames.h" 35 #include "core/dom/QualifiedName.h" 36 #include "core/dom/StaticNodeList.h" 37 #include "core/dom/shadow/ElementShadow.h" 38 #include "core/dom/shadow/ShadowRoot.h" 39 40 namespace WebCore { 41 42 using namespace HTMLNames; 43 44 InsertionPoint::InsertionPoint(const QualifiedName& tagName, Document* document) 45 : HTMLElement(tagName, document, CreateInsertionPoint) 46 , m_registeredWithShadowRoot(false) 47 { 48 setHasCustomStyleCallbacks(); 49 } 50 51 InsertionPoint::~InsertionPoint() 52 { 53 } 54 55 void InsertionPoint::attach(const AttachContext& context) 56 { 57 // FIXME: This loop shouldn't be needed since the distributed nodes should 58 // never be detached, we can probably remove it. 59 for (size_t i = 0; i < m_distribution.size(); ++i) { 60 if (!m_distribution.at(i)->attached()) 61 m_distribution.at(i)->attach(context); 62 } 63 64 HTMLElement::attach(context); 65 } 66 67 void InsertionPoint::detach(const AttachContext& context) 68 { 69 for (size_t i = 0; i < m_distribution.size(); ++i) 70 m_distribution.at(i)->lazyReattachIfAttached(); 71 72 HTMLElement::detach(context); 73 } 74 75 void InsertionPoint::willRecalcStyle(StyleChange change) 76 { 77 if (change < Inherit) 78 return; 79 for (size_t i = 0; i < m_distribution.size(); ++i) 80 m_distribution.at(i)->setNeedsStyleRecalc(LocalStyleChange); 81 } 82 83 bool InsertionPoint::shouldUseFallbackElements() const 84 { 85 return isActive() && !hasDistribution(); 86 } 87 88 bool InsertionPoint::isActive() const 89 { 90 if (!containingShadowRoot()) 91 return false; 92 const Node* node = parentNode(); 93 while (node) { 94 if (node->isInsertionPoint()) 95 return false; 96 97 node = node->parentNode(); 98 } 99 return true; 100 } 101 102 PassRefPtr<NodeList> InsertionPoint::getDistributedNodes() 103 { 104 document()->updateDistributionForNodeIfNeeded(this); 105 106 Vector<RefPtr<Node> > nodes; 107 for (size_t i = 0; i < m_distribution.size(); ++i) 108 nodes.append(m_distribution.at(i)); 109 110 return StaticNodeList::adopt(nodes); 111 } 112 113 bool InsertionPoint::rendererIsNeeded(const NodeRenderingContext& context) 114 { 115 return !isActive() && HTMLElement::rendererIsNeeded(context); 116 } 117 118 void InsertionPoint::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta) 119 { 120 HTMLElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta); 121 if (ShadowRoot* root = containingShadowRoot()) { 122 if (ElementShadow* rootOwner = root->owner()) 123 rootOwner->setNeedsDistributionRecalc(); 124 } 125 } 126 127 Node::InsertionNotificationRequest InsertionPoint::insertedInto(ContainerNode* insertionPoint) 128 { 129 HTMLElement::insertedInto(insertionPoint); 130 131 if (ShadowRoot* root = containingShadowRoot()) { 132 if (ElementShadow* rootOwner = root->owner()) { 133 rootOwner->setNeedsDistributionRecalc(); 134 if (isActive() && !m_registeredWithShadowRoot && insertionPoint->treeScope()->rootNode() == root) { 135 m_registeredWithShadowRoot = true; 136 root->ensureScopeDistribution()->registerInsertionPoint(this); 137 rootOwner->didAffectApplyAuthorStyles(); 138 if (canAffectSelector()) 139 rootOwner->willAffectSelector(); 140 } 141 } 142 } 143 144 return InsertionDone; 145 } 146 147 void InsertionPoint::removedFrom(ContainerNode* insertionPoint) 148 { 149 ShadowRoot* root = containingShadowRoot(); 150 if (!root) 151 root = insertionPoint->containingShadowRoot(); 152 153 if (root) { 154 if (ElementShadow* rootOwner = root->owner()) 155 rootOwner->setNeedsDistributionRecalc(); 156 } 157 158 // host can be null when removedFrom() is called from ElementShadow destructor. 159 ElementShadow* rootOwner = root ? root->owner() : 0; 160 161 // Since this insertion point is no longer visible from the shadow subtree, it need to clean itself up. 162 clearDistribution(); 163 164 if (m_registeredWithShadowRoot && insertionPoint->treeScope()->rootNode() == root) { 165 ASSERT(root); 166 m_registeredWithShadowRoot = false; 167 root->ensureScopeDistribution()->unregisterInsertionPoint(this); 168 if (rootOwner) { 169 rootOwner->didAffectApplyAuthorStyles(); 170 if (canAffectSelector()) 171 rootOwner->willAffectSelector(); 172 } 173 } 174 175 HTMLElement::removedFrom(insertionPoint); 176 } 177 178 void InsertionPoint::parseAttribute(const QualifiedName& name, const AtomicString& value) 179 { 180 if (name == reset_style_inheritanceAttr) { 181 if (!inDocument() || !attached() || !isActive()) 182 return; 183 containingShadowRoot()->host()->setNeedsStyleRecalc(); 184 } else 185 HTMLElement::parseAttribute(name, value); 186 } 187 188 bool InsertionPoint::resetStyleInheritance() const 189 { 190 return fastHasAttribute(reset_style_inheritanceAttr); 191 } 192 193 void InsertionPoint::setResetStyleInheritance(bool value) 194 { 195 setBooleanAttribute(reset_style_inheritanceAttr, value); 196 } 197 198 InsertionPoint* resolveReprojection(const Node* projectedNode) 199 { 200 InsertionPoint* insertionPoint = 0; 201 const Node* current = projectedNode; 202 203 while (current) { 204 if (ElementShadow* shadow = shadowOfParentForDistribution(current)) { 205 if (InsertionPoint* insertedTo = shadow->distributor().findInsertionPointFor(projectedNode)) { 206 current = insertedTo; 207 insertionPoint = insertedTo; 208 continue; 209 } 210 } 211 212 if (Node* parent = parentNodeForDistribution(current)) { 213 if (InsertionPoint* insertedTo = parent->isShadowRoot() ? toShadowRoot(parent)->insertionPoint() : 0) { 214 current = insertedTo; 215 insertionPoint = insertedTo; 216 continue; 217 } 218 } 219 220 break; 221 } 222 223 return insertionPoint; 224 } 225 226 void collectInsertionPointsWhereNodeIsDistributed(const Node* node, Vector<InsertionPoint*, 8>& results) 227 { 228 const Node* current = node; 229 while (true) { 230 if (ElementShadow* shadow = shadowOfParentForDistribution(current)) { 231 if (InsertionPoint* insertedTo = shadow->distributor().findInsertionPointFor(node)) { 232 current = insertedTo; 233 results.append(insertedTo); 234 continue; 235 } 236 } 237 if (Node* parent = parentNodeForDistribution(current)) { 238 if (InsertionPoint* insertedTo = parent->isShadowRoot() ? toShadowRoot(parent)->insertionPoint() : 0) { 239 current = insertedTo; 240 results.append(insertedTo); 241 continue; 242 } 243 } 244 return; 245 } 246 } 247 248 } // namespace WebCore 249