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(); } }
ContainerNode* FlatTreeTraversal::traverseParent(const Node& node, ParentTraversalDetails* details) { // TODO(hayato): Stop this hack for a pseudo element because a pseudo element is not a child of its parentOrShadowHostNode() in a flat tree. if (node.isPseudoElement()) return node.parentOrShadowHostNode(); if (node.isChildOfV1ShadowHost()) { HTMLSlotElement* slot = finalDestinationSlotFor(node); if (!slot) return nullptr; return traverseParent(*slot); } Element* parent = node.parentElement(); if (parent && isHTMLSlotElement(parent)) { HTMLSlotElement& slot = toHTMLSlotElement(*parent); if (!slot.assignedNodes().isEmpty()) return nullptr; return traverseParent(slot, details); } if (canBeDistributedToInsertionPoint(node)) return traverseParentForV0(node, details); DCHECK(!shadowWhereNodeCanBeDistributed(node)); return traverseParentOrHost(node); }
// TODO(hayato): This may return a wrong result for a node which is not in a // document flat tree. See FlatTreeTraversalTest's redistribution test for details. Node* FlatTreeTraversal::traverseSiblings(const Node& node, TraversalDirection direction) { if (node.isChildOfV1ShadowHost()) return traverseSiblingsForV1HostChild(node, direction); if (shadowWhereNodeCanBeDistributed(node)) return traverseSiblingsForV0Distribution(node, direction); if (Node* found = resolveDistributionStartingAt(direction == TraversalDirectionForward ? node.nextSibling() : node.previousSibling(), direction)) return found; if (!node.isInV0ShadowTree()) return nullptr; // For v0 older shadow tree if (node.parentNode() && node.parentNode()->isShadowRoot()) { ShadowRoot* parentShadowRoot = toShadowRoot(node.parentNode()); if (!parentShadowRoot->isYoungest()) { HTMLShadowElement* assignedInsertionPoint = parentShadowRoot->shadowInsertionPointOfYoungerShadowRoot(); DCHECK(assignedInsertionPoint); return traverseSiblings(*assignedInsertionPoint, direction); } } return nullptr; }
ContainerNode* FlatTreeTraversal::traverseParentForV0(const Node& node, ParentTraversalDetails* details) { if (shadowWhereNodeCanBeDistributed(node)) { if (const InsertionPoint* insertionPoint = resolveReprojection(&node)) { if (details) details->didTraverseInsertionPoint(insertionPoint); // The node is distributed. But the distribution was stopped at this insertion point. if (shadowWhereNodeCanBeDistributed(*insertionPoint)) return nullptr; return traverseParent(*insertionPoint); } return nullptr; } ContainerNode* parent = traverseParentOrHost(node); if (isActiveInsertionPoint(*parent)) return nullptr; return parent; }
// FIXME: Use an iterative algorithm so that it can be inlined. // https://bugs.webkit.org/show_bug.cgi?id=90415 Node* ComposedTreeWalker::traverseParent(const Node* node, ParentTraversalDetails* details) const { if (node->isPseudoElement()) return node->parentOrShadowHostNode(); if (shadowWhereNodeCanBeDistributed(*node)) { if (const InsertionPoint* insertionPoint = resolveReprojection(node)) { if (details) details->didTraverseInsertionPoint(insertionPoint); // The node is distributed. But the distribution was stopped at this insertion point. if (shadowWhereNodeCanBeDistributed(*insertionPoint)) return 0; return traverseParentOrHost(insertionPoint, details); } return 0; } return traverseParentOrHost(node, details); }
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()); }
Node* ComposedTreeWalker::traverseSiblingOrBackToInsertionPoint(const Node* node, TraversalDirection direction) { ASSERT(node); if (!shadowWhereNodeCanBeDistributed(*node)) return traverseSiblingInCurrentTree(node, direction); const 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); }