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::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(); } } }
Node* ComposedShadowTreeWalker::traverseSiblingOrBackToInsertionPoint(const Node* node, TraversalDirection direction) { ASSERT(node); ElementShadow* shadow = shadowOfParent(node); if (!shadow) return traverseSiblingInCurrentTree(node, direction); InsertionPoint* insertionPoint = shadow->insertionPointFor(node); if (!insertionPoint) return traverseSiblingInCurrentTree(node, direction); if (Node* next = (direction == TraversalDirectionForward ? insertionPoint->nextTo(node) : insertionPoint->previousTo(node))) return traverseNode(next, direction); return traverseSiblingOrBackToInsertionPoint(insertionPoint, direction); }
inline void DistributionPool::populateChildren(const ContainerNode* parent) { for (Node* child = parent->firstChild(); child; child = child->nextSibling()) { if (isActiveInsertionPoint(*child)) { InsertionPoint* insertionPoint = toInsertionPoint(child); for (size_t i = 0; i < insertionPoint->size(); ++i) m_nodes.append(insertionPoint->at(i)); } else { m_nodes.append(child); } } m_distributed.resize(m_nodes.size()); m_distributed.fill(false); }
void ElementShadow::distribute() { host()->setNeedsStyleRecalc(); Vector<HTMLShadowElement*, 32> shadowInsertionPoints; DistributionPool pool(*host()); for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) { HTMLShadowElement* shadowInsertionPoint = 0; const Vector<RefPtr<InsertionPoint> >& insertionPoints = root->descendantInsertionPoints(); for (size_t i = 0; i < insertionPoints.size(); ++i) { InsertionPoint* point = insertionPoints[i].get(); if (!point->isActive()) continue; if (isHTMLShadowElement(point)) { if (!shadowInsertionPoint) shadowInsertionPoint = toHTMLShadowElement(point); } else { pool.distributeTo(point, this); if (ElementShadow* shadow = shadowWhereNodeCanBeDistributed(*point)) shadow->setNeedsDistributionRecalc(); } } if (shadowInsertionPoint) { shadowInsertionPoints.append(shadowInsertionPoint); if (shadowInsertionPoint->hasChildNodes()) pool.populateChildren(*shadowInsertionPoint); } else { pool.clear(); } } for (size_t i = shadowInsertionPoints.size(); i > 0; --i) { HTMLShadowElement* shadowInsertionPoint = shadowInsertionPoints[i - 1]; ShadowRoot* root = shadowInsertionPoint->containingShadowRoot(); ASSERT(root); if (root->isOldest()) { pool.distributeTo(shadowInsertionPoint, this); } else if (root->olderShadowRoot()->type() == root->type()) { // Only allow reprojecting older shadow roots between the same type to // disallow reprojecting UA elements into author shadows. DistributionPool olderShadowRootPool(*root->olderShadowRoot()); olderShadowRootPool.distributeTo(shadowInsertionPoint, this); root->olderShadowRoot()->setShadowInsertionPointOfYoungerShadowRoot(shadowInsertionPoint); } if (ElementShadow* shadow = shadowWhereNodeCanBeDistributed(*shadowInsertionPoint)) shadow->setNeedsDistributionRecalc(); } }
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::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); }
inline void DistributionPool::populateChildren(const ContainerNode& parent) { clear(); for (Node* child = parent.firstChild(); child; child = child->nextSibling()) { if (isHTMLSlotElement(child)) { // TODO(hayato): Support re-distribution across v0 and v1 shadow trees continue; } if (isActiveInsertionPoint(*child)) { InsertionPoint* insertionPoint = toInsertionPoint(child); for (size_t i = 0; i < insertionPoint->distributedNodesSize(); ++i) m_nodes.append(insertionPoint->distributedNodeAt(i)); } else { m_nodes.append(child); } } m_distributed.resize(m_nodes.size()); m_distributed.fill(false); }
void ContentDistributor::distribute(Element* host) { ASSERT(needsDistribution()); ASSERT(m_nodeToInsertionPoint.isEmpty()); ASSERT(!host->containingShadowRoot() || host->containingShadowRoot()->distributor().isValid()); m_validity = Valid; if (ShadowRoot* root = host->shadowRoot()) { const Vector<RefPtr<InsertionPoint> >& insertionPoints = ensureInsertionPointList(root); for (size_t i = 0; i < insertionPoints.size(); ++i) { InsertionPoint* point = insertionPoints[i].get(); if (!point->isActive()) continue; distributeSelectionsTo(point, host); } } }
void ElementShadow::distributeV0() { host()->setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::Shadow)); WillBeHeapVector<RawPtrWillBeMember<HTMLShadowElement>, 32> shadowInsertionPoints; DistributionPool pool(*host()); for (ShadowRoot* root = &youngestShadowRoot(); root; root = root->olderShadowRoot()) { HTMLShadowElement* shadowInsertionPoint = 0; const WillBeHeapVector<RefPtrWillBeMember<InsertionPoint>>& insertionPoints = root->descendantInsertionPoints(); for (size_t i = 0; i < insertionPoints.size(); ++i) { InsertionPoint* point = insertionPoints[i].get(); if (!point->isActive()) continue; if (isHTMLShadowElement(*point)) { ASSERT(!shadowInsertionPoint); shadowInsertionPoint = toHTMLShadowElement(point); shadowInsertionPoints.append(shadowInsertionPoint); } else { pool.distributeTo(point, this); if (ElementShadow* shadow = shadowWhereNodeCanBeDistributed(*point)) shadow->setNeedsDistributionRecalc(); } } } for (size_t i = shadowInsertionPoints.size(); i > 0; --i) { HTMLShadowElement* shadowInsertionPoint = shadowInsertionPoints[i - 1]; ShadowRoot* root = shadowInsertionPoint->containingShadowRoot(); ASSERT(root); if (root->isOldest()) { pool.distributeTo(shadowInsertionPoint, this); } else if (root->olderShadowRoot()->type() == root->type()) { // Only allow reprojecting older shadow roots between the same type to // disallow reprojecting UA elements into author shadows. DistributionPool olderShadowRootPool(*root->olderShadowRoot()); olderShadowRootPool.distributeTo(shadowInsertionPoint, this); root->olderShadowRoot()->setShadowInsertionPointOfYoungerShadowRoot(shadowInsertionPoint); } if (ElementShadow* shadow = shadowWhereNodeCanBeDistributed(*shadowInsertionPoint)) shadow->setNeedsDistributionRecalc(); } InspectorInstrumentation::didPerformElementShadowDistribution(host()); }
static Node* traversePreviousSibling(const Node* node) { ASSERT(node); InsertionPoint* insertionPoint; if (nodeCanBeDistributed(node) && (insertionPoint = findInsertionPointOf(node))) { Node* found = findLastFromDistributedNode(insertionPoint->previousDistributedTo(node), insertionPoint); if (found) return found; return traversePreviousSibling(insertionPoint); } for (const Node* sibling = node->previousSibling(); sibling; sibling = sibling->previousSibling()) { if (Node* found = findLastEnteringInsertionPoints(sibling)) return found; } if (node->parentNode() && isActiveInsertionPoint(node->parentNode())) return traversePreviousSibling(node->parentNode()); return nullptr; }
bool ContentDistributor::invalidate(Element* host) { ASSERT(needsInvalidation()); bool needsReattach = (m_validity == Undetermined) || !m_nodeToInsertionPoint.isEmpty(); for (ShadowRoot* root = host->youngestShadowRoot(); root; root = root->olderShadowRoot()) { root->setAssignedTo(0); for (Node* node = root; node; node = node->traverseNextNode(root)) { if (!isInsertionPoint(node)) continue; needsReattach = needsReattach || true; InsertionPoint* point = toInsertionPoint(node); point->clearDistribution(); } } m_validity = Invalidating; m_nodeToInsertionPoint.clear(); return needsReattach; }
void EventPath::calculatePath() { ASSERT(m_node); ASSERT(m_nodeEventContexts.isEmpty()); m_node->document().updateDistributionForNodeIfNeeded(const_cast<Node*>(m_node)); Node* current = m_node; addNodeEventContext(current); if (!m_node->inDocument()) return; while (current) { if (current->isShadowRoot() && m_event && determineDispatchBehavior(m_event, toShadowRoot(current), m_node) == StayInsideShadowDOM) break; Vector<InsertionPoint*, 8> insertionPoints; collectDestinationInsertionPoints(*current, insertionPoints); if (!insertionPoints.isEmpty()) { for (size_t i = 0; i < insertionPoints.size(); ++i) { InsertionPoint* insertionPoint = insertionPoints[i]; if (insertionPoint->isShadowInsertionPoint()) { ShadowRoot* containingShadowRoot = insertionPoint->containingShadowRoot(); ASSERT(containingShadowRoot); if (!containingShadowRoot->isOldest()) addNodeEventContext(containingShadowRoot->olderShadowRoot()); } addNodeEventContext(insertionPoint); } current = insertionPoints.last(); continue; } if (current->isShadowRoot()) { current = current->shadowHost(); addNodeEventContext(current); } else { current = current->parentNode(); if (current) addNodeEventContext(current); } } }
Node* ComposedShadowTreeWalker::traverseSiblingOrBackToInsertionPoint(const Node* node, TraversalDirection direction) { ASSERT(node); ElementShadow* shadow = shadowOfParent(node); if (!shadow) return traverseSiblingInCurrentTree(node, direction); InsertionPoint* insertionPoint = resolveReprojection(node); if (!insertionPoint) return traverseSiblingInCurrentTree(node, direction); if (Node* found = traverseDistributedNodes(direction == TraversalDirectionForward ? insertionPoint->nextTo(node) : insertionPoint->previousTo(node), insertionPoint, direction)) return found; return traverseSiblingOrBackToInsertionPoint(insertionPoint, direction); }