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())); } } }
// 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; } }