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; }
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; }