void ContentDistributor::distribute(Element* host) { ASSERT(needsDistribution()); ASSERT(m_nodeToInsertionPoint.isEmpty()); ASSERT(!host->containingShadowRoot() || host->containingShadowRoot()->owner()->distributor().isValid()); m_validity = Valid; ContentDistribution pool; for (Node* node = host->firstChild(); node; node = node->nextSibling()) populate(node, pool); Vector<bool> distributed(pool.size()); distributed.fill(false); if (ShadowRoot* root = host->shadowRoot()) { if (ScopeContentDistribution* scope = root->scopeDistribution()) { const Vector<RefPtr<InsertionPoint> >& insertionPoints = scope->ensureInsertionPointList(root); for (size_t i = 0; i < insertionPoints.size(); ++i) { InsertionPoint* point = insertionPoints[i].get(); if (!point->isActive()) continue; distributeSelectionsTo(point, pool, distributed); if (ElementShadow* shadow = point->parentNode()->isElementNode() ? toElement(point->parentNode())->shadow() : 0) shadow->invalidateDistribution(); } } } }
void ContentDistributor::distributeNodeChildrenTo(InsertionPoint* insertionPoint, ContainerNode* containerNode) { ContentDistribution distribution; for (Node* node = containerNode->firstChild(); node; node = node->nextSibling()) { if (isActiveInsertionPoint(node)) { InsertionPoint* innerInsertionPoint = toInsertionPoint(node); if (innerInsertionPoint->hasDistribution()) { for (size_t i = 0; i < innerInsertionPoint->size(); ++i) { distribution.append(innerInsertionPoint->at(i)); if (!m_nodeToInsertionPoint.contains(innerInsertionPoint->at(i))) m_nodeToInsertionPoint.add(innerInsertionPoint->at(i), insertionPoint); } } else { for (Node* child = innerInsertionPoint->firstChild(); child; child = child->nextSibling()) { distribution.append(child); m_nodeToInsertionPoint.add(child, insertionPoint); } } } else { distribution.append(node); if (!m_nodeToInsertionPoint.contains(node)) m_nodeToInsertionPoint.add(node, insertionPoint); } } insertionPoint->setDistribution(distribution); }
void DistributionPool::distributeTo(InsertionPoint* insertionPoint, ElementShadow* elementShadow) { ContentDistribution distribution; for (size_t i = 0; i < m_nodes.size(); ++i) { if (m_distributed[i]) continue; if (isHTMLContentElement(*insertionPoint) && !toHTMLContentElement(insertionPoint)->canSelectNode(m_nodes, i)) continue; Node* node = m_nodes[i]; distribution.append(node); elementShadow->didDistributeNode(node, insertionPoint); m_distributed[i] = true; } // Distributes fallback elements if (insertionPoint->isContentInsertionPoint() && distribution.isEmpty()) { for (Node* fallbackNode = insertionPoint->firstChild(); fallbackNode; fallbackNode = fallbackNode->nextSibling()) { distribution.append(fallbackNode); elementShadow->didDistributeNode(fallbackNode, insertionPoint); } } insertionPoint->setDistribution(distribution); }
void ContentDistributor::distribute(Element* host) { ASSERT(needsDistribution()); ASSERT(m_nodeToInsertionPoint.isEmpty()); m_validity = Valid; ContentDistribution pool; for (Node* node = host->firstChild(); node; node = node->nextSibling()) populate(node, pool); Vector<bool> distributed(pool.size()); distributed.fill(false); Vector<HTMLShadowElement*, 8> activeShadowInsertionPoints; for (ShadowRoot* root = host->youngestShadowRoot(); root; root = root->olderShadowRoot()) { HTMLShadowElement* firstActiveShadowInsertionPoint = 0; const Vector<InsertionPoint*>& insertionPoints = root->insertionPointList(); for (size_t i = 0; i < insertionPoints.size(); ++i) { InsertionPoint* point = insertionPoints[i]; if (!point->isActive()) continue; if (isHTMLShadowElement(point)) { if (!firstActiveShadowInsertionPoint) firstActiveShadowInsertionPoint = toHTMLShadowElement(point); } else { distributeSelectionsTo(point, pool, distributed); if (ElementShadow* shadow = point->parentNode()->isElementNode() ? toElement(point->parentNode())->shadow() : 0) shadow->invalidateDistribution(); } } if (firstActiveShadowInsertionPoint) activeShadowInsertionPoints.append(firstActiveShadowInsertionPoint); } for (size_t i = activeShadowInsertionPoints.size(); i > 0; --i) { HTMLShadowElement* shadowElement = activeShadowInsertionPoints[i - 1]; ShadowRoot* root = shadowElement->shadowRoot(); ASSERT(root); if (root->olderShadowRoot()) { distributeNodeChildrenTo(shadowElement, root->olderShadowRoot()); root->olderShadowRoot()->setAssignedTo(shadowElement); } else { distributeSelectionsTo(shadowElement, pool, distributed); if (ElementShadow* shadow = shadowElement->parentNode()->isElementNode() ? toElement(shadowElement->parentNode())->shadow() : 0) shadow->invalidateDistribution(); } } }
void ContentDistributor::populate(Node* node, ContentDistribution& pool) { if (!isActiveInsertionPoint(node)) { pool.append(node); return; } InsertionPoint* insertionPoint = toInsertionPoint(node); if (insertionPoint->hasDistribution()) { for (size_t i = 0; i < insertionPoint->size(); ++i) populate(insertionPoint->at(i), pool); } else { for (Node* fallbackNode = insertionPoint->firstChild(); fallbackNode; fallbackNode = fallbackNode->nextSibling()) pool.append(fallbackNode); } }
void ContentDistributor::distributeSelectionsTo(InsertionPoint* insertionPoint, const ContentDistribution& pool, Vector<bool>& distributed) { ContentDistribution distribution; for (size_t i = 0; i < pool.size(); ++i) { if (distributed[i]) continue; if (insertionPoint->matchTypeFor(pool.nodes().at(i).get()) != InsertionPoint::AlwaysMatches) continue; Node* child = pool.at(i).get(); distribution.append(child); m_nodeToInsertionPoint.add(child, insertionPoint); distributed[i] = true; } insertionPoint->setDistribution(distribution); }
void ContentDistributor::distributeSelectionsTo(InsertionPoint* insertionPoint, const ContentDistribution& pool, Vector<bool>& distributed) { ContentDistribution distribution; ContentSelectorQuery query(insertionPoint); for (size_t i = 0; i < pool.size(); ++i) { if (distributed[i]) continue; if (!query.matches(pool.nodes(), i)) continue; Node* child = pool.at(i).get(); distribution.append(child); m_nodeToInsertionPoint.add(child, insertionPoint); distributed[i] = true; } insertionPoint->setDistribution(distribution); }
void InsertionPoint::setDistribution(ContentDistribution& distribution) { if (shouldUseFallbackElements()) { for (Node* child = firstChild(); child; child = child->nextSibling()) child->lazyReattachIfAttached(); } // Attempt not to reattach nodes that would be distributed to the exact same // location by comparing the old and new distributions. size_t i = 0; size_t j = 0; for ( ; i < m_distribution.size() && j < distribution.size(); ++i, ++j) { if (m_distribution.size() < distribution.size()) { // If the new distribution is larger than the old one, reattach all nodes in // the new distribution that were inserted. for ( ; j < distribution.size() && m_distribution.at(i) != distribution.at(j); ++j) distribution.at(j)->lazyReattachIfAttached(); } else if (m_distribution.size() > distribution.size()) { // If the old distribution is larger than the new one, reattach all nodes in // the old distribution that were removed. for ( ; i < m_distribution.size() && m_distribution.at(i) != distribution.at(j); ++i) m_distribution.at(i)->lazyReattachIfAttached(); } else if (m_distribution.at(i) != distribution.at(j)) { // If both distributions are the same length reattach both old and new. m_distribution.at(i)->lazyReattachIfAttached(); distribution.at(j)->lazyReattachIfAttached(); } } // If we hit the end of either list above we need to reattach all remaining nodes. for ( ; i < m_distribution.size(); ++i) m_distribution.at(i)->lazyReattachIfAttached(); for ( ; j < distribution.size(); ++j) distribution.at(j)->lazyReattachIfAttached(); m_distribution.swap(distribution); m_distribution.shrinkToFit(); }