| OLD | NEW |
| (Empty) |
| 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/ContentDistributor.h" | |
| 29 | |
| 30 #include "core/dom/NodeTraversal.h" | |
| 31 #include "core/dom/shadow/ElementShadow.h" | |
| 32 #include "core/dom/shadow/ShadowRoot.h" | |
| 33 #include "core/html/shadow/HTMLContentElement.h" | |
| 34 #include "core/html/shadow/HTMLShadowElement.h" | |
| 35 | |
| 36 namespace WebCore { | |
| 37 | |
| 38 void ContentDistribution::swap(ContentDistribution& other) | |
| 39 { | |
| 40 m_nodes.swap(other.m_nodes); | |
| 41 m_indices.swap(other.m_indices); | |
| 42 } | |
| 43 | |
| 44 void ContentDistribution::append(PassRefPtr<Node> node) | |
| 45 { | |
| 46 size_t size = m_nodes.size(); | |
| 47 m_indices.set(node.get(), size); | |
| 48 m_nodes.append(node); | |
| 49 } | |
| 50 | |
| 51 size_t ContentDistribution::find(const Node* node) const | |
| 52 { | |
| 53 HashMap<const Node*, size_t>::const_iterator it = m_indices.find(node); | |
| 54 if (it == m_indices.end()) | |
| 55 return notFound; | |
| 56 | |
| 57 return it.get()->value; | |
| 58 } | |
| 59 | |
| 60 Node* ContentDistribution::nextTo(const Node* node) const | |
| 61 { | |
| 62 size_t index = find(node); | |
| 63 if (index == notFound || index + 1 == size()) | |
| 64 return 0; | |
| 65 return at(index + 1).get(); | |
| 66 } | |
| 67 | |
| 68 Node* ContentDistribution::previousTo(const Node* node) const | |
| 69 { | |
| 70 size_t index = find(node); | |
| 71 if (index == notFound || !index) | |
| 72 return 0; | |
| 73 return at(index - 1).get(); | |
| 74 } | |
| 75 | |
| 76 | |
| 77 ScopeContentDistribution::ScopeContentDistribution() | |
| 78 : m_insertionPointAssignedTo(0) | |
| 79 , m_numberOfShadowElementChildren(0) | |
| 80 , m_numberOfContentElementChildren(0) | |
| 81 , m_numberOfElementShadowChildren(0) | |
| 82 , m_insertionPointListIsValid(false) | |
| 83 { | |
| 84 } | |
| 85 | |
| 86 void ScopeContentDistribution::setInsertionPointAssignedTo(PassRefPtr<InsertionP
oint> insertionPoint) | |
| 87 { | |
| 88 m_insertionPointAssignedTo = insertionPoint; | |
| 89 } | |
| 90 | |
| 91 void ScopeContentDistribution::invalidateInsertionPointList() | |
| 92 { | |
| 93 m_insertionPointListIsValid = false; | |
| 94 m_insertionPointList.clear(); | |
| 95 } | |
| 96 | |
| 97 const Vector<RefPtr<InsertionPoint> >& ScopeContentDistribution::ensureInsertion
PointList(ShadowRoot* shadowRoot) | |
| 98 { | |
| 99 if (m_insertionPointListIsValid) | |
| 100 return m_insertionPointList; | |
| 101 | |
| 102 m_insertionPointListIsValid = true; | |
| 103 ASSERT(m_insertionPointList.isEmpty()); | |
| 104 | |
| 105 if (!shadowRoot->containsInsertionPoints()) | |
| 106 return m_insertionPointList; | |
| 107 | |
| 108 for (Element* element = ElementTraversal::firstWithin(shadowRoot); element;
element = ElementTraversal::next(element, shadowRoot)) { | |
| 109 if (element->isInsertionPoint()) | |
| 110 m_insertionPointList.append(toInsertionPoint(element)); | |
| 111 } | |
| 112 | |
| 113 return m_insertionPointList; | |
| 114 } | |
| 115 | |
| 116 void ScopeContentDistribution::registerInsertionPoint(InsertionPoint* point) | |
| 117 { | |
| 118 if (isHTMLShadowElement(point)) | |
| 119 ++m_numberOfShadowElementChildren; | |
| 120 else if (isHTMLContentElement(point)) | |
| 121 ++m_numberOfContentElementChildren; | |
| 122 else | |
| 123 ASSERT_NOT_REACHED(); | |
| 124 | |
| 125 invalidateInsertionPointList(); | |
| 126 } | |
| 127 | |
| 128 void ScopeContentDistribution::unregisterInsertionPoint(InsertionPoint* point) | |
| 129 { | |
| 130 if (isHTMLShadowElement(point)) | |
| 131 --m_numberOfShadowElementChildren; | |
| 132 else if (isHTMLContentElement(point)) | |
| 133 --m_numberOfContentElementChildren; | |
| 134 else | |
| 135 ASSERT_NOT_REACHED(); | |
| 136 | |
| 137 ASSERT(m_numberOfContentElementChildren >= 0); | |
| 138 ASSERT(m_numberOfShadowElementChildren >= 0); | |
| 139 | |
| 140 invalidateInsertionPointList(); | |
| 141 } | |
| 142 | |
| 143 ContentDistributor::ContentDistributor() | |
| 144 : m_needsSelectFeatureSet(false) | |
| 145 { | |
| 146 } | |
| 147 | |
| 148 ContentDistributor::~ContentDistributor() | |
| 149 { | |
| 150 } | |
| 151 | |
| 152 InsertionPoint* ContentDistributor::findInsertionPointFor(const Node* key) const | |
| 153 { | |
| 154 return m_nodeToInsertionPoint.get(key); | |
| 155 } | |
| 156 | |
| 157 void ContentDistributor::populate(Node* node, Vector<Node*>& pool) | |
| 158 { | |
| 159 if (!isActiveInsertionPoint(node)) { | |
| 160 pool.append(node); | |
| 161 return; | |
| 162 } | |
| 163 | |
| 164 InsertionPoint* insertionPoint = toInsertionPoint(node); | |
| 165 if (insertionPoint->hasDistribution()) { | |
| 166 for (size_t i = 0; i < insertionPoint->size(); ++i) | |
| 167 populate(insertionPoint->at(i), pool); | |
| 168 } else { | |
| 169 for (Node* fallbackNode = insertionPoint->firstChild(); fallbackNode; fa
llbackNode = fallbackNode->nextSibling()) | |
| 170 pool.append(fallbackNode); | |
| 171 } | |
| 172 } | |
| 173 | |
| 174 void ContentDistributor::distribute(Element* host) | |
| 175 { | |
| 176 Vector<Node*> pool; | |
| 177 for (Node* node = host->firstChild(); node; node = node->nextSibling()) | |
| 178 populate(node, pool); | |
| 179 | |
| 180 host->setNeedsStyleRecalc(); | |
| 181 | |
| 182 Vector<bool> distributed(pool.size()); | |
| 183 distributed.fill(false); | |
| 184 | |
| 185 Vector<HTMLShadowElement*, 8> activeShadowInsertionPoints; | |
| 186 for (ShadowRoot* root = host->youngestShadowRoot(); root; root = root->older
ShadowRoot()) { | |
| 187 HTMLShadowElement* firstActiveShadowInsertionPoint = 0; | |
| 188 | |
| 189 if (ScopeContentDistribution* scope = root->scopeDistribution()) { | |
| 190 const Vector<RefPtr<InsertionPoint> >& insertionPoints = scope->ensu
reInsertionPointList(root); | |
| 191 for (size_t i = 0; i < insertionPoints.size(); ++i) { | |
| 192 InsertionPoint* point = insertionPoints[i].get(); | |
| 193 if (!point->isActive()) | |
| 194 continue; | |
| 195 | |
| 196 if (isHTMLShadowElement(point)) { | |
| 197 if (!firstActiveShadowInsertionPoint) | |
| 198 firstActiveShadowInsertionPoint = toHTMLShadowElement(po
int); | |
| 199 } else { | |
| 200 distributeSelectionsTo(point, pool, distributed); | |
| 201 if (ElementShadow* shadow = shadowOfParentForDistribution(po
int)) | |
| 202 shadow->setNeedsDistributionRecalc(); | |
| 203 } | |
| 204 } | |
| 205 } | |
| 206 | |
| 207 if (firstActiveShadowInsertionPoint) | |
| 208 activeShadowInsertionPoints.append(firstActiveShadowInsertionPoint); | |
| 209 } | |
| 210 | |
| 211 for (size_t i = activeShadowInsertionPoints.size(); i > 0; --i) { | |
| 212 HTMLShadowElement* shadowElement = activeShadowInsertionPoints[i - 1]; | |
| 213 ShadowRoot* root = shadowElement->containingShadowRoot(); | |
| 214 ASSERT(root); | |
| 215 if (!shadowElement->shouldSelect()) { | |
| 216 if (root->olderShadowRoot()) | |
| 217 root->olderShadowRoot()->ensureScopeDistribution()->setInsertion
PointAssignedTo(shadowElement); | |
| 218 } else if (root->olderShadowRoot()) { | |
| 219 distributeNodeChildrenTo(shadowElement, root->olderShadowRoot()); | |
| 220 root->olderShadowRoot()->ensureScopeDistribution()->setInsertionPoin
tAssignedTo(shadowElement); | |
| 221 } else { | |
| 222 distributeSelectionsTo(shadowElement, pool, distributed); | |
| 223 } | |
| 224 if (ElementShadow* shadow = shadowOfParentForDistribution(shadowElement)
) | |
| 225 shadow->setNeedsDistributionRecalc(); | |
| 226 } | |
| 227 | |
| 228 // Detach all nodes that were not distributed and have a renderer. | |
| 229 for (size_t i = 0; i < pool.size(); ++i) { | |
| 230 if (distributed[i]) | |
| 231 continue; | |
| 232 if (pool[i]->renderer()) | |
| 233 pool[i]->lazyReattachIfAttached(); | |
| 234 } | |
| 235 } | |
| 236 | |
| 237 void ContentDistributor::distributeSelectionsTo(InsertionPoint* insertionPoint,
const Vector<Node*>& pool, Vector<bool>& distributed) | |
| 238 { | |
| 239 ContentDistribution distribution; | |
| 240 | |
| 241 for (size_t i = 0; i < pool.size(); ++i) { | |
| 242 if (distributed[i]) | |
| 243 continue; | |
| 244 | |
| 245 if (isHTMLContentElement(insertionPoint) && !toHTMLContentElement(insert
ionPoint)->canSelectNode(pool, i)) | |
| 246 continue; | |
| 247 | |
| 248 Node* child = pool[i]; | |
| 249 distribution.append(child); | |
| 250 m_nodeToInsertionPoint.add(child, insertionPoint); | |
| 251 distributed[i] = true; | |
| 252 } | |
| 253 | |
| 254 insertionPoint->setDistribution(distribution); | |
| 255 } | |
| 256 | |
| 257 void ContentDistributor::distributeNodeChildrenTo(InsertionPoint* insertionPoint
, ContainerNode* containerNode) | |
| 258 { | |
| 259 ContentDistribution distribution; | |
| 260 for (Node* node = containerNode->firstChild(); node; node = node->nextSiblin
g()) { | |
| 261 if (isActiveInsertionPoint(node)) { | |
| 262 InsertionPoint* innerInsertionPoint = toInsertionPoint(node); | |
| 263 if (innerInsertionPoint->hasDistribution()) { | |
| 264 for (size_t i = 0; i < innerInsertionPoint->size(); ++i) { | |
| 265 distribution.append(innerInsertionPoint->at(i)); | |
| 266 m_nodeToInsertionPoint.add(innerInsertionPoint->at(i), inser
tionPoint); | |
| 267 } | |
| 268 } else { | |
| 269 for (Node* child = innerInsertionPoint->firstChild(); child; chi
ld = child->nextSibling()) { | |
| 270 distribution.append(child); | |
| 271 m_nodeToInsertionPoint.add(child, insertionPoint); | |
| 272 } | |
| 273 } | |
| 274 } else { | |
| 275 distribution.append(node); | |
| 276 m_nodeToInsertionPoint.add(node, insertionPoint); | |
| 277 } | |
| 278 } | |
| 279 | |
| 280 insertionPoint->setDistribution(distribution); | |
| 281 } | |
| 282 | |
| 283 const SelectRuleFeatureSet& ContentDistributor::ensureSelectFeatureSet(ElementSh
adow* shadow) | |
| 284 { | |
| 285 if (!m_needsSelectFeatureSet) | |
| 286 return m_selectFeatures; | |
| 287 | |
| 288 m_selectFeatures.clear(); | |
| 289 for (ShadowRoot* root = shadow->oldestShadowRoot(); root; root = root->young
erShadowRoot()) | |
| 290 collectSelectFeatureSetFrom(root); | |
| 291 m_needsSelectFeatureSet = false; | |
| 292 return m_selectFeatures; | |
| 293 } | |
| 294 | |
| 295 void ContentDistributor::collectSelectFeatureSetFrom(ShadowRoot* root) | |
| 296 { | |
| 297 if (!root->containsShadowRoots() && !root->containsContentElements()) | |
| 298 return; | |
| 299 | |
| 300 for (Element* element = ElementTraversal::firstWithin(root); element; elemen
t = ElementTraversal::next(element, root)) { | |
| 301 if (ElementShadow* shadow = element->shadow()) | |
| 302 m_selectFeatures.add(shadow->ensureSelectFeatureSet()); | |
| 303 if (!isHTMLContentElement(element)) | |
| 304 continue; | |
| 305 const CSSSelectorList& list = toHTMLContentElement(element)->selectorLis
t(); | |
| 306 for (const CSSSelector* selector = list.first(); selector; selector = CS
SSelectorList::next(selector)) { | |
| 307 for (const CSSSelector* component = selector; component; component =
component->tagHistory()) | |
| 308 m_selectFeatures.collectFeaturesFromSelector(component); | |
| 309 } | |
| 310 } | |
| 311 } | |
| 312 | |
| 313 void ContentDistributor::didAffectSelector(Element* host, AffectedSelectorMask m
ask) | |
| 314 { | |
| 315 if (ensureSelectFeatureSet(host->shadow()).hasSelectorFor(mask)) | |
| 316 host->shadow()->setNeedsDistributionRecalc(); | |
| 317 } | |
| 318 | |
| 319 void ContentDistributor::willAffectSelector(Element* host) | |
| 320 { | |
| 321 for (ElementShadow* shadow = host->shadow(); shadow; shadow = shadow->contai
ningShadow()) { | |
| 322 if (shadow->distributor().needsSelectFeatureSet()) | |
| 323 break; | |
| 324 shadow->distributor().setNeedsSelectFeatureSet(); | |
| 325 } | |
| 326 host->shadow()->setNeedsDistributionRecalc(); | |
| 327 } | |
| 328 | |
| 329 void ContentDistributor::clearDistribution(Element* host) | |
| 330 { | |
| 331 m_nodeToInsertionPoint.clear(); | |
| 332 | |
| 333 for (ShadowRoot* root = host->youngestShadowRoot(); root; root = root->older
ShadowRoot()) { | |
| 334 if (ScopeContentDistribution* scope = root->scopeDistribution()) | |
| 335 scope->setInsertionPointAssignedTo(0); | |
| 336 } | |
| 337 } | |
| 338 | |
| 339 } | |
| OLD | NEW |