void expectSiblingInvalidation(unsigned maxDirectAdjacentSelectors, const AtomicString& siblingName, InvalidationSetVector& invalidationSets)
 {
     EXPECT_EQ(1u, invalidationSets.size());
     const SiblingInvalidationSet& siblingInvalidationSet = toSiblingInvalidationSet(*invalidationSets[0]);
     HashSet<AtomicString> classes = classSet(siblingInvalidationSet);
     EXPECT_EQ(1u, classes.size());
     EXPECT_TRUE(classes.contains(siblingName));
     EXPECT_EQ(maxDirectAdjacentSelectors, siblingInvalidationSet.maxDirectAdjacentSelectors());
 }
void StyleInvalidator::scheduleSiblingInvalidationsAsDescendants(const InvalidationLists& invalidationLists, ContainerNode& schedulingParent)
{
    if (invalidationLists.siblings.isEmpty())
        return;

    PendingInvalidations& pendingInvalidations = ensurePendingInvalidations(schedulingParent);

    for (auto& invalidationSet : invalidationLists.siblings) {
        if (invalidationSet->invalidatesSelf() && !pendingInvalidations.descendants().contains(invalidationSet))
            pendingInvalidations.descendants().append(invalidationSet);

        if (DescendantInvalidationSet* descendants = toSiblingInvalidationSet(*invalidationSet).siblingDescendants()) {
            if (!pendingInvalidations.descendants().contains(descendants))
                pendingInvalidations.descendants().append(descendants);
        }
    }
    schedulingParent.setNeedsStyleInvalidation();
}
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()));
        }
    }
}
Exemple #5
0
// selector is the selector immediately to the left of the rightmost combinator.
// siblingFeatures is null if selector is not immediately to the left of a sibling combinator.
// descendantFeatures has the features of the rightmost compound selector.
void RuleFeatureSet::addFeaturesToInvalidationSets(const CSSSelector* selector, InvalidationSetFeatures* siblingFeatures, InvalidationSetFeatures& descendantFeatures)
{
    const CSSSelector* lastCompoundSelectorInAdjacentChain = selector;

    // We set siblingFeatures to &localFeatures if we find a rightmost sibling combinator.
    InvalidationSetFeatures localFeatures;

    for (const CSSSelector* current = selector; current; current = current->tagHistory()) {
        InvalidationType type = siblingFeatures ? InvalidateSiblings : InvalidateDescendants;
        if (InvalidationSet* invalidationSet = invalidationSetForSelector(*current, type)) {
            if (siblingFeatures) {
                SiblingInvalidationSet* siblingInvalidationSet = toSiblingInvalidationSet(invalidationSet);
                siblingInvalidationSet->updateMaxDirectAdjacentSelectors(siblingFeatures->maxDirectAdjacentSelectors);

                addFeaturesToInvalidationSet(*invalidationSet, *siblingFeatures);
                if (siblingFeatures == &descendantFeatures)
                    siblingInvalidationSet->descendants().setInvalidatesSelf();
                else
                    addFeaturesToInvalidationSet(siblingInvalidationSet->descendants(), descendantFeatures);
            } else {
                addFeaturesToInvalidationSet(*invalidationSet, descendantFeatures);
            }
        } else {
            if (current->isHostPseudoClass())
                descendantFeatures.treeBoundaryCrossing = true;
            if (current->isInsertionPointCrossing())
                descendantFeatures.insertionPointCrossing = true;
            if (const CSSSelectorList* selectorList = current->selectorList()) {
                ASSERT(supportsInvalidationWithSelectorList(current->pseudoType()));
                for (const CSSSelector* subSelector = selectorList->first(); subSelector; subSelector = CSSSelectorList::next(*subSelector))
                    addFeaturesToInvalidationSets(subSelector, siblingFeatures, descendantFeatures);
            }
        }

        if (current->relation() == CSSSelector::SubSelector)
            continue;

        if (current->isShadowSelector())
            descendantFeatures.treeBoundaryCrossing = true;

        if (!current->isAdjacentSelector()) {
            lastCompoundSelectorInAdjacentChain = current->tagHistory();
            siblingFeatures = nullptr;
            continue;
        }

        if (siblingFeatures) {
            if (siblingFeatures->maxDirectAdjacentSelectors == UINT_MAX)
                continue;

            if (current->relation() == CSSSelector::DirectAdjacent)
                siblingFeatures->maxDirectAdjacentSelectors++;
            else
                siblingFeatures->maxDirectAdjacentSelectors = UINT_MAX;
            continue;
        }

        localFeatures = InvalidationSetFeatures();
        auto result = extractInvalidationSetFeatures(*lastCompoundSelectorInAdjacentChain, localFeatures, Ancestor);
        ASSERT(result.first);
        localFeatures.forceSubtree = result.second == ForceSubtree;
        siblingFeatures = &localFeatures;
    }
}