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 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 ElementShadowV0::distribute() { HeapVector<Member<HTMLShadowElement>, 32> shadowInsertionPoints; DistributionPool pool(m_elementShadow->host()); for (ShadowRoot* root = &youngestShadowRoot(); root; root = root->olderShadowRoot()) { HTMLShadowElement* shadowInsertionPoint = 0; for (const auto& point : root->descendantInsertionPoints()) { if (!point->isActive()) continue; if (isHTMLShadowElement(*point)) { DCHECK(!shadowInsertionPoint); shadowInsertionPoint = toHTMLShadowElement(point); shadowInsertionPoints.append(shadowInsertionPoint); } else { pool.distributeTo(point, this); if (ElementShadow* shadow = shadowWhereNodeCanBeDistributedForV0(*point)) shadow->setNeedsDistributionRecalc(); } } } for (size_t i = shadowInsertionPoints.size(); i > 0; --i) { HTMLShadowElement* shadowInsertionPoint = shadowInsertionPoints[i - 1]; ShadowRoot* root = shadowInsertionPoint->containingShadowRoot(); DCHECK(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 = shadowWhereNodeCanBeDistributedForV0(*shadowInsertionPoint)) shadow->setNeedsDistributionRecalc(); } InspectorInstrumentation::didPerformElementShadowDistribution( &m_elementShadow->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()); }
nsIContent* ExplicitChildIterator::GetNextChild() { // If we're already in the inserted-children array, look there first if (mIndexInInserted) { MOZ_ASSERT(mChild); MOZ_ASSERT(nsContentUtils::IsContentInsertionPoint(mChild)); MOZ_ASSERT(!mDefaultChild); MatchedNodes assignedChildren = GetMatchedNodesForPoint(mChild); if (mIndexInInserted < assignedChildren.Length()) { return assignedChildren[mIndexInInserted++]; } mIndexInInserted = 0; mChild = mChild->GetNextSibling(); } else if (mShadowIterator) { // If we're inside of a <shadow> element, look through the // explicit children of the projected ShadowRoot via // the mShadowIterator. nsIContent* nextChild = mShadowIterator->GetNextChild(); if (nextChild) { return nextChild; } mShadowIterator = nullptr; mChild = mChild->GetNextSibling(); } else if (mDefaultChild) { // If we're already in default content, check if there are more nodes there MOZ_ASSERT(mChild); MOZ_ASSERT(nsContentUtils::IsContentInsertionPoint(mChild)); mDefaultChild = mDefaultChild->GetNextSibling(); if (mDefaultChild) { return mDefaultChild; } mChild = mChild->GetNextSibling(); } else if (mIsFirst) { // at the beginning of the child list mChild = mParent->GetFirstChild(); mIsFirst = false; } else if (mChild) { // in the middle of the child list mChild = mChild->GetNextSibling(); } // Iterate until we find a non-insertion point, or an insertion point with // content. while (mChild) { // If the current child being iterated is a shadow insertion point then // the iterator needs to go into the projected ShadowRoot. if (ShadowRoot::IsShadowInsertionPoint(mChild)) { // Look for the next child in the projected ShadowRoot for the <shadow> // element. HTMLShadowElement* shadowElem = static_cast<HTMLShadowElement*>(mChild); ShadowRoot* projectedShadow = shadowElem->GetOlderShadowRoot(); if (projectedShadow) { mShadowIterator = new ExplicitChildIterator(projectedShadow); nsIContent* nextChild = mShadowIterator->GetNextChild(); if (nextChild) { return nextChild; } mShadowIterator = nullptr; } mChild = mChild->GetNextSibling(); } else if (nsContentUtils::IsContentInsertionPoint(mChild)) { // If the current child being iterated is a content insertion point // then the iterator needs to return the nodes distributed into // the content insertion point. MatchedNodes assignedChildren = GetMatchedNodesForPoint(mChild); if (!assignedChildren.IsEmpty()) { // Iterate through elements projected on insertion point. mIndexInInserted = 1; return assignedChildren[0]; } // Insertion points inside fallback/default content // are considered inactive and do not get assigned nodes. mDefaultChild = mChild->GetFirstChild(); if (mDefaultChild) { return mDefaultChild; } // If we have an insertion point with no assigned nodes and // no default content, move on to the next node. mChild = mChild->GetNextSibling(); } else { // mChild is not an insertion point, thus it is the next node to // return from this iterator. break; } } return mChild; }
nsIContent* ExplicitChildIterator::GetPreviousChild() { // If we're already in the inserted-children array, look there first if (mIndexInInserted) { // NB: mIndexInInserted points one past the last returned child so we need // to look *two* indices back in order to return the previous child. MatchedNodes assignedChildren = GetMatchedNodesForPoint(mChild); if (--mIndexInInserted) { return assignedChildren[mIndexInInserted - 1]; } mChild = mChild->GetPreviousSibling(); } else if (mShadowIterator) { nsIContent* previousChild = mShadowIterator->GetPreviousChild(); if (previousChild) { return previousChild; } mShadowIterator = nullptr; mChild = mChild->GetPreviousSibling(); } else if (mDefaultChild) { // If we're already in default content, check if there are more nodes there mDefaultChild = mDefaultChild->GetPreviousSibling(); if (mDefaultChild) { return mDefaultChild; } mChild = mChild->GetPreviousSibling(); } else if (mIsFirst) { // at the beginning of the child list return nullptr; } else if (mChild) { // in the middle of the child list mChild = mChild->GetPreviousSibling(); } else { // at the end of the child list mChild = mParent->GetLastChild(); } // Iterate until we find a non-insertion point, or an insertion point with // content. while (mChild) { if (ShadowRoot::IsShadowInsertionPoint(mChild)) { // If the current child being iterated is a shadow insertion point then // the iterator needs to go into the projected ShadowRoot. HTMLShadowElement* shadowElem = static_cast<HTMLShadowElement*>(mChild); ShadowRoot* projectedShadow = shadowElem->GetOlderShadowRoot(); if (projectedShadow) { // Create a ExplicitChildIterator that begins iterating from the end. mShadowIterator = new ExplicitChildIterator(projectedShadow, false); nsIContent* previousChild = mShadowIterator->GetPreviousChild(); if (previousChild) { return previousChild; } mShadowIterator = nullptr; } mChild = mChild->GetPreviousSibling(); } else if (nsContentUtils::IsContentInsertionPoint(mChild)) { // If the current child being iterated is a content insertion point // then the iterator needs to return the nodes distributed into // the content insertion point. MatchedNodes assignedChildren = GetMatchedNodesForPoint(mChild); if (!assignedChildren.IsEmpty()) { mIndexInInserted = assignedChildren.Length(); return assignedChildren[mIndexInInserted - 1]; } mDefaultChild = mChild->GetLastChild(); if (mDefaultChild) { return mDefaultChild; } mChild = mChild->GetPreviousSibling(); } else { // mChild is not an insertion point, thus it is the next node to // return from this iterator. break; } } if (!mChild) { mIsFirst = true; } return mChild; }