| Index: Source/core/css/invalidation/StyleInvalidator.cpp
|
| diff --git a/Source/core/css/invalidation/StyleInvalidator.cpp b/Source/core/css/invalidation/StyleInvalidator.cpp
|
| index f35d30bee26f77a0f33070c8827d67bf0049f1c8..0e77fc07ff164cd4f849ebc9099a744c8a49ff07 100644
|
| --- a/Source/core/css/invalidation/StyleInvalidator.cpp
|
| +++ b/Source/core/css/invalidation/StyleInvalidator.cpp
|
| @@ -33,40 +33,52 @@ static const unsigned char* s_tracingEnabled = nullptr;
|
| void StyleInvalidator::invalidate(Document& document)
|
| {
|
| RecursionData recursionData;
|
| + SiblingData siblingData;
|
| if (Element* documentElement = document.documentElement())
|
| - invalidate(*documentElement, recursionData);
|
| + invalidate(*documentElement, recursionData, siblingData);
|
| document.clearChildNeedsStyleInvalidation();
|
| document.clearNeedsStyleInvalidation();
|
| - clearPendingInvalidations();
|
| + m_pendingInvalidationMap.clear();
|
| }
|
|
|
| -void StyleInvalidator::scheduleInvalidation(PassRefPtrWillBeRawPtr<InvalidationSet> invalidationSet, Element& element)
|
| +void StyleInvalidator::scheduleInvalidationSetsForElement(const InvalidationLists& invalidationLists, Element& element)
|
| {
|
| ASSERT(element.inActiveDocument());
|
| if (element.styleChangeType() >= SubtreeStyleChange)
|
| return;
|
| - if (invalidationSet->wholeSubtreeInvalid()) {
|
| - element.setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::StyleInvalidator));
|
| - clearInvalidation(element);
|
| - return;
|
| +
|
| + bool requiresDescendantInvalidation = false;
|
| +
|
| + for (auto& invalidationSet : invalidationLists.descendants) {
|
| + if (invalidationSet->wholeSubtreeInvalid()) {
|
| + element.setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::StyleInvalidator));
|
| + clearInvalidation(element);
|
| + return;
|
| + }
|
| +
|
| + if (invalidationSet->invalidatesSelf())
|
| + element.setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::StyleInvalidator));
|
| +
|
| + if (!invalidationSet->isEmpty())
|
| + requiresDescendantInvalidation = true;
|
| }
|
| - if (invalidationSet->invalidatesSelf())
|
| - element.setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::StyleInvalidator));
|
|
|
| - if (invalidationSet->isEmpty())
|
| + if (invalidationLists.siblings.isEmpty() && !requiresDescendantInvalidation)
|
| return;
|
|
|
| - InvalidationList& list = ensurePendingInvalidationList(element);
|
| - list.append(invalidationSet);
|
| element.setNeedsStyleInvalidation();
|
| -}
|
| + PendingInvalidations& pendingInvalidations = ensurePendingInvalidations(element);
|
| + for (auto& invalidationSet : invalidationLists.siblings)
|
| + pendingInvalidations.siblings().append(invalidationSet);
|
|
|
| -StyleInvalidator::InvalidationList& StyleInvalidator::ensurePendingInvalidationList(Element& element)
|
| -{
|
| - PendingInvalidationMap::AddResult addResult = m_pendingInvalidationMap.add(&element, nullptr);
|
| - if (addResult.isNewEntry)
|
| - addResult.storedValue->value = adoptPtrWillBeNoop(new InvalidationList);
|
| - return *addResult.storedValue->value;
|
| + if (!requiresDescendantInvalidation)
|
| + return;
|
| +
|
| + for (auto& invalidationSet : invalidationLists.descendants) {
|
| + ASSERT(!invalidationSet->wholeSubtreeInvalid());
|
| + if (!invalidationSet->isEmpty())
|
| + pendingInvalidations.descendants().append(invalidationSet);
|
| + }
|
| }
|
|
|
| void StyleInvalidator::clearInvalidation(Element& element)
|
| @@ -77,9 +89,12 @@ void StyleInvalidator::clearInvalidation(Element& element)
|
| element.clearNeedsStyleInvalidation();
|
| }
|
|
|
| -void StyleInvalidator::clearPendingInvalidations()
|
| +PendingInvalidations& StyleInvalidator::ensurePendingInvalidations(Element& element)
|
| {
|
| - m_pendingInvalidationMap.clear();
|
| + PendingInvalidationMap::AddResult addResult = m_pendingInvalidationMap.add(&element, nullptr);
|
| + if (addResult.isNewEntry)
|
| + addResult.storedValue->value = PendingInvalidations::create();
|
| + return *addResult.storedValue->value;
|
| }
|
|
|
| StyleInvalidator::StyleInvalidator()
|
| @@ -105,7 +120,7 @@ void StyleInvalidator::RecursionData::pushInvalidationSet(const InvalidationSet&
|
| m_invalidateCustomPseudo = invalidationSet.customPseudoInvalid();
|
| }
|
|
|
| -ALWAYS_INLINE bool StyleInvalidator::RecursionData::matchesCurrentInvalidationSets(Element& element)
|
| +ALWAYS_INLINE bool StyleInvalidator::RecursionData::matchesCurrentInvalidationSets(Element& element) const
|
| {
|
| if (m_invalidateCustomPseudo && element.shadowPseudoId() != nullAtom) {
|
| TRACE_STYLE_INVALIDATOR_INVALIDATION_IF_ENABLED(element, InvalidateCustomPseudo);
|
| @@ -123,53 +138,114 @@ ALWAYS_INLINE bool StyleInvalidator::RecursionData::matchesCurrentInvalidationSe
|
| return false;
|
| }
|
|
|
| -ALWAYS_INLINE bool StyleInvalidator::checkInvalidationSetsAgainstElement(Element& element, StyleInvalidator::RecursionData& recursionData)
|
| +void StyleInvalidator::SiblingData::pushInvalidationSet(const InvalidationSet& invalidationSet)
|
| +{
|
| + unsigned invalidationLimit;
|
| + if (invalidationSet.maxDirectAdjacentSelectors() == std::numeric_limits<unsigned>::max())
|
| + invalidationLimit = std::numeric_limits<unsigned>::max();
|
| + else
|
| + invalidationLimit = m_elementIndex + invalidationSet.maxDirectAdjacentSelectors();
|
| + m_invalidationEntries.append(Entry(&invalidationSet, invalidationLimit));
|
| +}
|
| +
|
| +ALWAYS_INLINE 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] = m_invalidationEntries.last();
|
| + m_invalidationEntries.removeLast();
|
| + continue;
|
| + }
|
| +
|
| + const InvalidationSet* invalidationSet = m_invalidationEntries[index].m_invalidationSet.get();
|
| +
|
| + if (invalidationSet->invalidatesElement(element)) {
|
| + const InvalidationSet* descendants = invalidationSet->descendants();
|
| + ASSERT(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;
|
| +}
|
| +
|
| +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 (element.needsStyleInvalidation()) {
|
| - if (InvalidationList* invalidationList = m_pendingInvalidationMap.get(&element)) {
|
| - for (const auto& invalidationSet : *invalidationList)
|
| + thisElementNeedsStyleRecalc |= siblingData.matchCurrentInvalidationSets(element, recursionData);
|
| +
|
| + if (UNLIKELY(element.needsStyleInvalidation())) {
|
| + PendingInvalidations* pendingInvalidations = m_pendingInvalidationMap.get(&element);
|
| + ASSERT(pendingInvalidations);
|
| +
|
| + for (const auto& invalidationSet : pendingInvalidations->siblings())
|
| + siblingData.pushInvalidationSet(*invalidationSet);
|
| +
|
| + 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(element, *invalidationList));
|
| + "data", InspectorStyleInvalidatorInvalidateEvent::invalidationList(element, pendingInvalidations->descendants()));
|
| }
|
| }
|
| }
|
| return thisElementNeedsStyleRecalc;
|
| }
|
|
|
| -bool StyleInvalidator::invalidateChildren(Element& element, StyleInvalidator::RecursionData& recursionData)
|
| +bool StyleInvalidator::invalidateChildren(Element& element, RecursionData& recursionData)
|
| {
|
| + SiblingData siblingData;
|
| bool someChildrenNeedStyleRecalc = false;
|
| for (ShadowRoot* root = element.youngestShadowRoot(); root; root = root->olderShadowRoot()) {
|
| if (!recursionData.treeBoundaryCrossing() && !root->childNeedsStyleInvalidation() && !root->needsStyleInvalidation())
|
| continue;
|
| for (Element* child = ElementTraversal::firstChild(*root); child; child = ElementTraversal::nextSibling(*child)) {
|
| - bool childRecalced = invalidate(*child, recursionData);
|
| + bool childRecalced = invalidate(*child, recursionData, siblingData);
|
| someChildrenNeedStyleRecalc = someChildrenNeedStyleRecalc || childRecalced;
|
| }
|
| root->clearChildNeedsStyleInvalidation();
|
| root->clearNeedsStyleInvalidation();
|
| }
|
| for (Element* child = ElementTraversal::firstChild(element); child; child = ElementTraversal::nextSibling(*child)) {
|
| - bool childRecalced = invalidate(*child, recursionData);
|
| + bool childRecalced = invalidate(*child, recursionData, siblingData);
|
| someChildrenNeedStyleRecalc = someChildrenNeedStyleRecalc || childRecalced;
|
| }
|
| return someChildrenNeedStyleRecalc;
|
| }
|
|
|
| -bool StyleInvalidator::invalidate(Element& element, StyleInvalidator::RecursionData& recursionData)
|
| +bool StyleInvalidator::invalidate(Element& element, RecursionData& recursionData, SiblingData& siblingData)
|
| {
|
| RecursionCheckpoint checkpoint(&recursionData);
|
| + siblingData.advance();
|
|
|
| - bool thisElementNeedsStyleRecalc = checkInvalidationSetsAgainstElement(element, recursionData);
|
| + bool thisElementNeedsStyleRecalc = checkInvalidationSetsAgainstElement(element, recursionData, siblingData);
|
|
|
| bool someChildrenNeedStyleRecalc = false;
|
| if (recursionData.hasInvalidationSets() || element.childNeedsStyleInvalidation())
|
|
|