Index: Source/core/css/invalidation/StyleInvalidator.cpp |
diff --git a/Source/core/css/invalidation/StyleInvalidator.cpp b/Source/core/css/invalidation/StyleInvalidator.cpp |
index ddc28c70b6e8607355a4e9245bac2d1f5bca3d2d..d116bf5867fb7d1dd91ca06d4cea8e991d2248e6 100644 |
--- a/Source/core/css/invalidation/StyleInvalidator.cpp |
+++ b/Source/core/css/invalidation/StyleInvalidator.cpp |
@@ -33,36 +33,40 @@ 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(); |
} |
-void StyleInvalidator::scheduleInvalidation(PassRefPtrWillBeRawPtr<DescendantInvalidationSet> invalidationSet, Element& element) |
+void StyleInvalidator::scheduleInvalidation(PassRefPtrWillBeRawPtr<DescendantInvalidationSet> invalidationSet, Element& element, InvalidateType type) |
{ |
ASSERT(element.inActiveDocument()); |
- if (element.styleChangeType() >= SubtreeStyleChange) |
- return; |
- if (invalidationSet->wholeSubtreeInvalid()) { |
- element.setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::StyleInvalidator)); |
- clearInvalidation(element); |
- return; |
- } |
- if (invalidationSet->isEmpty()) { |
- element.setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::StyleInvalidator)); |
- return; |
+ if (type == InvalidateDescendants) { |
+ if (element.styleChangeType() >= SubtreeStyleChange) |
+ return; |
+ if (invalidationSet->wholeSubtreeInvalid()) { |
+ element.setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::StyleInvalidator)); |
+ clearInvalidation(element); |
+ return; |
+ } |
+ if (invalidationSet->isEmpty()) { |
+ element.setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::StyleInvalidator)); |
+ return; |
+ } |
+ element.setNeedsStyleInvalidation(); |
+ } else { |
+ element.markAncestorsWithChildNeedsStyleInvalidation(); |
} |
- |
- InvalidationList& list = ensurePendingInvalidationList(element); |
+ InvalidationList& list = ensurePendingInvalidationList(element, type); |
list.append(invalidationSet); |
- element.setNeedsStyleInvalidation(); |
} |
-StyleInvalidator::InvalidationList& StyleInvalidator::ensurePendingInvalidationList(Element& element) |
+StyleInvalidator::InvalidationList& StyleInvalidator::ensurePendingInvalidationList(Element& element, InvalidateType type) |
{ |
- PendingInvalidationMap::AddResult addResult = m_pendingInvalidationMap.add(&element, nullptr); |
+ PendingInvalidationMap::AddResult addResult = m_pendingInvalidationMap[type].add(&element, nullptr); |
if (addResult.isNewEntry) |
addResult.storedValue->value = adoptPtrWillBeNoop(new InvalidationList); |
return *addResult.storedValue->value; |
@@ -72,13 +76,15 @@ void StyleInvalidator::clearInvalidation(Element& element) |
{ |
if (!element.needsStyleInvalidation()) |
return; |
- m_pendingInvalidationMap.remove(&element); |
+ m_pendingInvalidationMap[InvalidateDescendants].remove(&element); |
+ m_pendingInvalidationMap[InvalidateSiblings].remove(&element); |
element.clearNeedsStyleInvalidation(); |
} |
void StyleInvalidator::clearPendingInvalidations() |
{ |
- m_pendingInvalidationMap.clear(); |
+ m_pendingInvalidationMap[InvalidateDescendants].clear(); |
+ m_pendingInvalidationMap[InvalidateSiblings].clear(); |
} |
StyleInvalidator::StyleInvalidator() |
@@ -104,7 +110,7 @@ void StyleInvalidator::RecursionData::pushInvalidationSet(const DescendantInvali |
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); |
@@ -122,6 +128,30 @@ ALWAYS_INLINE bool StyleInvalidator::RecursionData::matchesCurrentInvalidationSe |
return false; |
} |
+void StyleInvalidator::SiblingData::pushInvalidationSet(const DescendantInvalidationSet& invalidationSet) |
+{ |
+ m_invalidationSets.append(&invalidationSet); |
+ if (invalidationSet.maxDirectAdjacentSelectors() == std::numeric_limits<unsigned>::max()) |
+ m_invalidationLimits.append(std::numeric_limits<unsigned>::max()); |
+ else |
+ m_invalidationLimits.append(m_elementIndex + invalidationSet.maxDirectAdjacentSelectors()); |
+} |
+ |
+ALWAYS_INLINE bool StyleInvalidator::SiblingData::matchesCurrentInvalidationSets(Element& element) |
+{ |
+ m_elementIndex++; |
+ |
+ for (unsigned index = 0; index < m_invalidationLimits.size(); ++index) { |
+ if (m_elementIndex > m_invalidationLimits[index]) |
+ continue; |
+ |
+ if (m_invalidationSets[index]->wholeSubtreeInvalid() || m_invalidationSets[index]->invalidatesElement(element)) |
+ return true; |
+ } |
+ |
+ return false; |
+} |
+ |
ALWAYS_INLINE bool StyleInvalidator::checkInvalidationSetsAgainstElement(Element& element, StyleInvalidator::RecursionData& recursionData) |
{ |
if (element.styleChangeType() >= SubtreeStyleChange || recursionData.wholeSubtreeInvalid()) { |
@@ -129,7 +159,7 @@ ALWAYS_INLINE bool StyleInvalidator::checkInvalidationSetsAgainstElement(Element |
return false; |
} |
if (element.needsStyleInvalidation()) { |
- if (InvalidationList* invalidationList = m_pendingInvalidationMap.get(&element)) { |
+ if (InvalidationList* invalidationList = m_pendingInvalidationMap[InvalidateDescendants].get(&element)) { |
for (const auto& invalidationSet : *invalidationList) |
recursionData.pushInvalidationSet(*invalidationSet); |
if (UNLIKELY(*s_tracingEnabled)) { |
@@ -147,28 +177,34 @@ ALWAYS_INLINE bool StyleInvalidator::checkInvalidationSetsAgainstElement(Element |
bool StyleInvalidator::invalidateChildren(Element& element, StyleInvalidator::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, StyleInvalidator::RecursionData& recursionData, SiblingData& siblingData) |
{ |
RecursionCheckpoint checkpoint(&recursionData); |
+ if (siblingData.matchesCurrentInvalidationSets(element)) { |
+ element.setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::StyleInvalidator)); |
+ } |
+ |
bool thisElementNeedsStyleRecalc = checkInvalidationSetsAgainstElement(element, recursionData); |
bool someChildrenNeedStyleRecalc = false; |
@@ -194,13 +230,20 @@ bool StyleInvalidator::invalidate(Element& element, StyleInvalidator::RecursionD |
element.clearChildNeedsStyleInvalidation(); |
element.clearNeedsStyleInvalidation(); |
+ if (InvalidationList* invalidationList = m_pendingInvalidationMap[InvalidateSiblings].get(&element)) { |
+ for (const auto& invalidationSet : *invalidationList) { |
+ siblingData.pushInvalidationSet(*invalidationSet); |
+ } |
+ } |
+ |
return thisElementNeedsStyleRecalc; |
} |
DEFINE_TRACE(StyleInvalidator) |
{ |
#if ENABLE(OILPAN) |
- visitor->trace(m_pendingInvalidationMap); |
+ visitor->trace(m_pendingInvalidationMap[InvalidateDescendants]); |
+ visitor->trace(m_pendingInvalidationMap[InvalidateSiblings]); |
#endif |
} |