bool StyleInvalidator::invalidate(Element& element, RecursionData& recursionData, SiblingData& siblingData)
{
    siblingData.advance();
    RecursionCheckpoint checkpoint(&recursionData);

    bool thisElementNeedsStyleRecalc = checkInvalidationSetsAgainstElement(element, recursionData, siblingData);

    bool someChildrenNeedStyleRecalc = false;
    if (recursionData.hasInvalidationSets() || element.childNeedsStyleInvalidation())
        someChildrenNeedStyleRecalc = invalidateChildren(element, recursionData);

    if (thisElementNeedsStyleRecalc) {
        ASSERT(!recursionData.wholeSubtreeInvalid());
        element.setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::StyleInvalidator));
    } else if (recursionData.hasInvalidationSets() && someChildrenNeedStyleRecalc) {
        // Clone the ComputedStyle in order to preserve correct style sharing, if possible. Otherwise recalc style.
        if (LayoutObject* layoutObject = element.layoutObject()) {
            layoutObject->setStyleInternal(ComputedStyle::clone(layoutObject->styleRef()));
        } else {
            TRACE_STYLE_INVALIDATOR_INVALIDATION_IF_ENABLED(element, PreventStyleSharingForParent);
            element.setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::StyleInvalidator));
        }
    }

    if (recursionData.insertionPointCrossing() && element.isInsertionPoint())
        element.setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::StyleInvalidator));

    element.clearChildNeedsStyleInvalidation();
    element.clearNeedsStyleInvalidation();

    return thisElementNeedsStyleRecalc;
}
bool StyleInvalidator::SiblingData::matchCurrentInvalidationSets(Element& element, RecursionData& recursionData)
{
    bool thisElementNeedsStyleRecalc = false;
    ASSERT(!recursionData.wholeSubtreeInvalid());

    unsigned index = 0;
    while (index < m_invalidationEntries.size()) {
        if (m_elementIndex > m_invalidationEntries[index].m_invalidationLimit) {
            // m_invalidationEntries[index] only applies to earlier siblings. Remove it.
            m_invalidationEntries[index] = m_invalidationEntries.last();
            m_invalidationEntries.removeLast();
            continue;
        }

        const SiblingInvalidationSet& invalidationSet = *m_invalidationEntries[index].m_invalidationSet;
        ++index;
        if (!invalidationSet.invalidatesElement(element))
            continue;

        if (invalidationSet.invalidatesSelf())
            thisElementNeedsStyleRecalc = true;

        if (const DescendantInvalidationSet* descendants = invalidationSet.siblingDescendants()) {
            if (descendants->wholeSubtreeInvalid()) {
                element.setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::StyleInvalidator));
                return true;
            }

            if (!descendants->isEmpty())
                recursionData.pushInvalidationSet(*descendants);
        }

    }
    return thisElementNeedsStyleRecalc;
}
ALWAYS_INLINE bool StyleInvalidator::checkInvalidationSetsAgainstElement(Element& element, RecursionData& recursionData, SiblingData& siblingData)
{
    if (element.styleChangeType() >= SubtreeStyleChange || recursionData.wholeSubtreeInvalid()) {
        recursionData.setWholeSubtreeInvalid();
        return false;
    }

    bool thisElementNeedsStyleRecalc = recursionData.matchesCurrentInvalidationSets(element);
    if (UNLIKELY(!siblingData.isEmpty()))
        thisElementNeedsStyleRecalc |= siblingData.matchCurrentInvalidationSets(element, recursionData);

    if (UNLIKELY(element.needsStyleInvalidation()))
        pushInvalidationSetsForElement(element, recursionData, siblingData);
    return thisElementNeedsStyleRecalc;
}
void StyleInvalidator::invalidateSlotDistributedElements(HTMLSlotElement& slot, const RecursionData& recursionData) const
{
    for (auto& distributedNode : slot.getDistributedNodes()) {
        if (distributedNode->needsStyleRecalc())
            continue;
        if (!distributedNode->isElementNode())
            continue;
        if (recursionData.matchesCurrentInvalidationSetsAsSlotted(toElement(*distributedNode)))
            distributedNode->setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::StyleInvalidator));
    }
}
bool StyleInvalidator::SiblingData::matchCurrentInvalidationSets(Element& element, RecursionData& recursionData) const
{
    bool thisElementNeedsStyleRecalc = false;
    ASSERT(!recursionData.wholeSubtreeInvalid());

    unsigned index = 0;
    while (index < m_invalidationEntries.size()) {
        if (m_elementIndex > m_invalidationEntries[index].m_invalidationLimit) {
            // m_invalidationEntries[index] only applies to earlier siblings. Remove it.
            m_invalidationEntries[index] = m_invalidationEntries.last();
            m_invalidationEntries.removeLast();
            continue;
        }

        const SiblingInvalidationSet& invalidationSet = *m_invalidationEntries[index].m_invalidationSet;

        if (invalidationSet.invalidatesElement(element)) {
            const DescendantInvalidationSet& descendants = invalidationSet.descendants();
            if (descendants.wholeSubtreeInvalid()) {
                // Avoid directly setting SubtreeStyleChange on element, or ContainerNode::checkForChildrenAdjacentRuleChanges()
                // may propagate the SubtreeStyleChange to our own siblings' subtrees.

                for (Element* child = ElementTraversal::firstChild(element); child; child = ElementTraversal::nextSibling(*child)) {
                    child->setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::SiblingSelector));
                }
                return true;
            }

            if (descendants.invalidatesSelf())
                thisElementNeedsStyleRecalc = true;

            if (!descendants.isEmpty())
                recursionData.pushInvalidationSet(descendants);
        }

        ++index;
    }
    return thisElementNeedsStyleRecalc;
}
bool StyleInvalidator::invalidateShadowRootChildren(Element& element, RecursionData& recursionData)
{
    bool someChildrenNeedStyleRecalc = false;
    for (ShadowRoot* root = element.youngestShadowRoot(); root; root = root->olderShadowRoot()) {
        if (!recursionData.treeBoundaryCrossing() && !root->childNeedsStyleInvalidation() && !root->needsStyleInvalidation())
            continue;
        SiblingData siblingData;
        for (Element* child = ElementTraversal::firstChild(*root); child; child = ElementTraversal::nextSibling(*child)) {
            bool childRecalced = invalidate(*child, recursionData, siblingData);
            someChildrenNeedStyleRecalc = someChildrenNeedStyleRecalc || childRecalced;
        }
        root->clearChildNeedsStyleInvalidation();
        root->clearNeedsStyleInvalidation();
    }
    return someChildrenNeedStyleRecalc;
}
void StyleInvalidator::pushInvalidationSetsForElement(Element& element, RecursionData& recursionData, SiblingData& siblingData)
{
    PendingInvalidations* pendingInvalidations = m_pendingInvalidationMap.get(&element);
    ASSERT(pendingInvalidations);

    for (const auto& invalidationSet : pendingInvalidations->siblings())
        siblingData.pushInvalidationSet(toSiblingInvalidationSet(*invalidationSet));

    if (!pendingInvalidations->descendants().isEmpty()) {
        for (const auto& invalidationSet : pendingInvalidations->descendants())
            recursionData.pushInvalidationSet(toDescendantInvalidationSet(*invalidationSet));
        if (UNLIKELY(*s_tracingEnabled)) {
            TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.invalidationTracking"),
                "StyleInvalidatorInvalidationTracking",
                TRACE_EVENT_SCOPE_THREAD,
                "data", InspectorStyleInvalidatorInvalidateEvent::invalidationList(element, pendingInvalidations->descendants()));
        }
    }
}
void StyleInvalidator::pushInvalidationSetsForContainerNode(ContainerNode& node, RecursionData& recursionData, SiblingData& siblingData)
{
    PendingInvalidations* pendingInvalidations = m_pendingInvalidationMap.get(&node);
    ASSERT(pendingInvalidations);

    for (const auto& invalidationSet : pendingInvalidations->siblings())
        siblingData.pushInvalidationSet(toSiblingInvalidationSet(*invalidationSet));

    if (node.getStyleChangeType() >= SubtreeStyleChange)
        return;

    if (!pendingInvalidations->descendants().isEmpty()) {
        for (const auto& invalidationSet : pendingInvalidations->descendants())
            recursionData.pushInvalidationSet(*invalidationSet);
        if (UNLIKELY(*s_tracingEnabled)) {
            TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.invalidationTracking"),
                "StyleInvalidatorInvalidationTracking",
                TRACE_EVENT_SCOPE_THREAD,
                "data", InspectorStyleInvalidatorInvalidateEvent::invalidationList(node, pendingInvalidations->descendants()));
        }
    }
}