| OLD | NEW |
| 1 | 1 |
| 2 // Copyright 2014 The Chromium Authors. All rights reserved. | 2 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 3 // Use of this source code is governed by a BSD-style license that can be | 3 // Use of this source code is governed by a BSD-style license that can be |
| 4 // found in the LICENSE file. | 4 // found in the LICENSE file. |
| 5 | 5 |
| 6 #include "config.h" | 6 #include "config.h" |
| 7 | 7 |
| 8 #include "core/css/invalidation/StyleInvalidator.h" | 8 #include "core/css/invalidation/StyleInvalidator.h" |
| 9 | 9 |
| 10 #include "core/css/invalidation/InvalidationSet.h" | 10 #include "core/css/invalidation/InvalidationSet.h" |
| (...skipping 15 matching lines...) Expand all Loading... |
| 26 // with InvalidationSet to avoid additional GOT lookup cost. | 26 // with InvalidationSet to avoid additional GOT lookup cost. |
| 27 static const unsigned char* s_tracingEnabled = nullptr; | 27 static const unsigned char* s_tracingEnabled = nullptr; |
| 28 | 28 |
| 29 #define TRACE_STYLE_INVALIDATOR_INVALIDATION_IF_ENABLED(element, reason) \ | 29 #define TRACE_STYLE_INVALIDATOR_INVALIDATION_IF_ENABLED(element, reason) \ |
| 30 if (UNLIKELY(*s_tracingEnabled)) \ | 30 if (UNLIKELY(*s_tracingEnabled)) \ |
| 31 TRACE_STYLE_INVALIDATOR_INVALIDATION(element, reason); | 31 TRACE_STYLE_INVALIDATOR_INVALIDATION(element, reason); |
| 32 | 32 |
| 33 void StyleInvalidator::invalidate(Document& document) | 33 void StyleInvalidator::invalidate(Document& document) |
| 34 { | 34 { |
| 35 RecursionData recursionData; | 35 RecursionData recursionData; |
| 36 SiblingData siblingData; |
| 36 if (Element* documentElement = document.documentElement()) | 37 if (Element* documentElement = document.documentElement()) |
| 37 invalidate(*documentElement, recursionData); | 38 invalidate(*documentElement, recursionData, siblingData); |
| 38 document.clearChildNeedsStyleInvalidation(); | 39 document.clearChildNeedsStyleInvalidation(); |
| 39 document.clearNeedsStyleInvalidation(); | 40 document.clearNeedsStyleInvalidation(); |
| 40 clearPendingInvalidations(); | 41 m_pendingInvalidationMap.clear(); |
| 41 } | 42 } |
| 42 | 43 |
| 43 void StyleInvalidator::scheduleInvalidation(PassRefPtrWillBeRawPtr<InvalidationS
et> invalidationSet, Element& element) | 44 void StyleInvalidator::scheduleInvalidationSetsForElement(const InvalidationList
s& invalidationLists, Element& element) |
| 44 { | 45 { |
| 45 ASSERT(element.inActiveDocument()); | 46 ASSERT(element.inActiveDocument()); |
| 46 if (element.styleChangeType() >= SubtreeStyleChange) | 47 if (element.styleChangeType() >= SubtreeStyleChange) |
| 47 return; | 48 return; |
| 48 if (invalidationSet->wholeSubtreeInvalid()) { | 49 |
| 49 element.setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTrac
ing::create(StyleChangeReason::StyleInvalidator)); | 50 bool requiresDescendantInvalidation = false; |
| 50 clearInvalidation(element); | 51 |
| 51 return; | 52 for (auto& invalidationSet : invalidationLists.descendants) { |
| 53 if (invalidationSet->wholeSubtreeInvalid()) { |
| 54 element.setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonFor
Tracing::create(StyleChangeReason::StyleInvalidator)); |
| 55 clearInvalidation(element); |
| 56 return; |
| 57 } |
| 58 |
| 59 if (invalidationSet->invalidatesSelf()) |
| 60 element.setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTr
acing::create(StyleChangeReason::StyleInvalidator)); |
| 61 |
| 62 if (!invalidationSet->isEmpty()) |
| 63 requiresDescendantInvalidation = true; |
| 52 } | 64 } |
| 53 if (invalidationSet->invalidatesSelf()) | |
| 54 element.setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracin
g::create(StyleChangeReason::StyleInvalidator)); | |
| 55 | 65 |
| 56 if (invalidationSet->isEmpty()) | 66 if (invalidationLists.siblings.isEmpty() && !requiresDescendantInvalidation) |
| 57 return; | 67 return; |
| 58 | 68 |
| 59 InvalidationList& list = ensurePendingInvalidationList(element); | |
| 60 list.append(invalidationSet); | |
| 61 element.setNeedsStyleInvalidation(); | 69 element.setNeedsStyleInvalidation(); |
| 62 } | 70 PendingInvalidations& pendingInvalidations = ensurePendingInvalidations(elem
ent); |
| 71 for (auto& invalidationSet : invalidationLists.siblings) |
| 72 pendingInvalidations.siblings().append(invalidationSet); |
| 63 | 73 |
| 64 StyleInvalidator::InvalidationList& StyleInvalidator::ensurePendingInvalidationL
ist(Element& element) | 74 if (!requiresDescendantInvalidation) |
| 65 { | 75 return; |
| 66 PendingInvalidationMap::AddResult addResult = m_pendingInvalidationMap.add(&
element, nullptr); | 76 |
| 67 if (addResult.isNewEntry) | 77 for (auto& invalidationSet : invalidationLists.descendants) { |
| 68 addResult.storedValue->value = adoptPtrWillBeNoop(new InvalidationList); | 78 ASSERT(!invalidationSet->wholeSubtreeInvalid()); |
| 69 return *addResult.storedValue->value; | 79 if (!invalidationSet->isEmpty()) |
| 80 pendingInvalidations.descendants().append(invalidationSet); |
| 81 } |
| 70 } | 82 } |
| 71 | 83 |
| 72 void StyleInvalidator::clearInvalidation(Element& element) | 84 void StyleInvalidator::clearInvalidation(Element& element) |
| 73 { | 85 { |
| 74 if (!element.needsStyleInvalidation()) | 86 if (!element.needsStyleInvalidation()) |
| 75 return; | 87 return; |
| 76 m_pendingInvalidationMap.remove(&element); | 88 m_pendingInvalidationMap.remove(&element); |
| 77 element.clearNeedsStyleInvalidation(); | 89 element.clearNeedsStyleInvalidation(); |
| 78 } | 90 } |
| 79 | 91 |
| 80 void StyleInvalidator::clearPendingInvalidations() | 92 PendingInvalidations& StyleInvalidator::ensurePendingInvalidations(Element& elem
ent) |
| 81 { | 93 { |
| 82 m_pendingInvalidationMap.clear(); | 94 PendingInvalidationMap::AddResult addResult = m_pendingInvalidationMap.add(&
element, nullptr); |
| 95 if (addResult.isNewEntry) |
| 96 addResult.storedValue->value = PendingInvalidations::create(); |
| 97 return *addResult.storedValue->value; |
| 83 } | 98 } |
| 84 | 99 |
| 85 StyleInvalidator::StyleInvalidator() | 100 StyleInvalidator::StyleInvalidator() |
| 86 { | 101 { |
| 87 s_tracingEnabled = TRACE_EVENT_API_GET_CATEGORY_ENABLED(TRACE_DISABLED_BY_DE
FAULT("devtools.timeline.invalidationTracking")); | 102 s_tracingEnabled = TRACE_EVENT_API_GET_CATEGORY_ENABLED(TRACE_DISABLED_BY_DE
FAULT("devtools.timeline.invalidationTracking")); |
| 88 InvalidationSet::cacheTracingFlag(); | 103 InvalidationSet::cacheTracingFlag(); |
| 89 } | 104 } |
| 90 | 105 |
| 91 StyleInvalidator::~StyleInvalidator() | 106 StyleInvalidator::~StyleInvalidator() |
| 92 { | 107 { |
| 93 } | 108 } |
| 94 | 109 |
| 95 void StyleInvalidator::RecursionData::pushInvalidationSet(const InvalidationSet&
invalidationSet) | 110 void StyleInvalidator::RecursionData::pushInvalidationSet(const InvalidationSet&
invalidationSet) |
| 96 { | 111 { |
| 97 ASSERT(!m_wholeSubtreeInvalid); | 112 ASSERT(!m_wholeSubtreeInvalid); |
| 98 ASSERT(!invalidationSet.wholeSubtreeInvalid()); | 113 ASSERT(!invalidationSet.wholeSubtreeInvalid()); |
| 99 ASSERT(!invalidationSet.isEmpty()); | 114 ASSERT(!invalidationSet.isEmpty()); |
| 100 if (invalidationSet.treeBoundaryCrossing()) | 115 if (invalidationSet.treeBoundaryCrossing()) |
| 101 m_treeBoundaryCrossing = true; | 116 m_treeBoundaryCrossing = true; |
| 102 if (invalidationSet.insertionPointCrossing()) | 117 if (invalidationSet.insertionPointCrossing()) |
| 103 m_insertionPointCrossing = true; | 118 m_insertionPointCrossing = true; |
| 104 m_invalidationSets.append(&invalidationSet); | 119 m_invalidationSets.append(&invalidationSet); |
| 105 m_invalidateCustomPseudo = invalidationSet.customPseudoInvalid(); | 120 m_invalidateCustomPseudo = invalidationSet.customPseudoInvalid(); |
| 106 } | 121 } |
| 107 | 122 |
| 108 ALWAYS_INLINE bool StyleInvalidator::RecursionData::matchesCurrentInvalidationSe
ts(Element& element) | 123 ALWAYS_INLINE bool StyleInvalidator::RecursionData::matchesCurrentInvalidationSe
ts(Element& element) const |
| 109 { | 124 { |
| 110 if (m_invalidateCustomPseudo && element.shadowPseudoId() != nullAtom) { | 125 if (m_invalidateCustomPseudo && element.shadowPseudoId() != nullAtom) { |
| 111 TRACE_STYLE_INVALIDATOR_INVALIDATION_IF_ENABLED(element, InvalidateCusto
mPseudo); | 126 TRACE_STYLE_INVALIDATOR_INVALIDATION_IF_ENABLED(element, InvalidateCusto
mPseudo); |
| 112 return true; | 127 return true; |
| 113 } | 128 } |
| 114 | 129 |
| 115 if (m_insertionPointCrossing && element.isInsertionPoint()) | 130 if (m_insertionPointCrossing && element.isInsertionPoint()) |
| 116 return true; | 131 return true; |
| 117 | 132 |
| 118 for (const auto& invalidationSet : m_invalidationSets) { | 133 for (const auto& invalidationSet : m_invalidationSets) { |
| 119 if (invalidationSet->invalidatesElement(element)) | 134 if (invalidationSet->invalidatesElement(element)) |
| 120 return true; | 135 return true; |
| 121 } | 136 } |
| 122 | 137 |
| 123 return false; | 138 return false; |
| 124 } | 139 } |
| 125 | 140 |
| 126 ALWAYS_INLINE bool StyleInvalidator::checkInvalidationSetsAgainstElement(Element
& element, StyleInvalidator::RecursionData& recursionData) | 141 void StyleInvalidator::SiblingData::pushInvalidationSet(const InvalidationSet& i
nvalidationSet) |
| 142 { |
| 143 unsigned invalidationLimit; |
| 144 if (invalidationSet.maxDirectAdjacentSelectors() == std::numeric_limits<unsi
gned>::max()) |
| 145 invalidationLimit = std::numeric_limits<unsigned>::max(); |
| 146 else |
| 147 invalidationLimit = m_elementIndex + invalidationSet.maxDirectAdjacentSe
lectors(); |
| 148 m_invalidationEntries.append(Entry(&invalidationSet, invalidationLimit)); |
| 149 } |
| 150 |
| 151 ALWAYS_INLINE bool StyleInvalidator::SiblingData::matchCurrentInvalidationSets(E
lement& element, RecursionData& recursionData) |
| 152 { |
| 153 bool thisElementNeedsStyleRecalc = false; |
| 154 ASSERT(!recursionData.wholeSubtreeInvalid()); |
| 155 |
| 156 unsigned index = 0; |
| 157 while (index < m_invalidationEntries.size()) { |
| 158 if (m_elementIndex > m_invalidationEntries[index].m_invalidationLimit) { |
| 159 m_invalidationEntries[index] = m_invalidationEntries.last(); |
| 160 m_invalidationEntries.removeLast(); |
| 161 continue; |
| 162 } |
| 163 |
| 164 const InvalidationSet* invalidationSet = m_invalidationEntries[index].m_
invalidationSet.get(); |
| 165 |
| 166 if (invalidationSet->invalidatesElement(element)) { |
| 167 const InvalidationSet* descendants = invalidationSet->descendants(); |
| 168 ASSERT(descendants); |
| 169 if (descendants->wholeSubtreeInvalid()) { |
| 170 // Avoid directly setting SubtreeStyleChange on element, or Cont
ainerNode::checkForChildrenAdjacentRuleChanges() |
| 171 // may propagate the SubtreeStyleChange to our own siblings' sub
trees. |
| 172 |
| 173 for (Element* child = ElementTraversal::firstChild(element); chi
ld; child = ElementTraversal::nextSibling(*child)) { |
| 174 child->setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeRe
asonForTracing::create(StyleChangeReason::SiblingSelector)); |
| 175 } |
| 176 return true; |
| 177 } |
| 178 |
| 179 if (descendants->invalidatesSelf()) |
| 180 thisElementNeedsStyleRecalc = true; |
| 181 |
| 182 if (!descendants->isEmpty()) |
| 183 recursionData.pushInvalidationSet(*descendants); |
| 184 } |
| 185 |
| 186 ++index; |
| 187 } |
| 188 return thisElementNeedsStyleRecalc; |
| 189 } |
| 190 |
| 191 ALWAYS_INLINE bool StyleInvalidator::checkInvalidationSetsAgainstElement(Element
& element, RecursionData& recursionData, SiblingData& siblingData) |
| 127 { | 192 { |
| 128 if (element.styleChangeType() >= SubtreeStyleChange || recursionData.wholeSu
btreeInvalid()) { | 193 if (element.styleChangeType() >= SubtreeStyleChange || recursionData.wholeSu
btreeInvalid()) { |
| 129 recursionData.setWholeSubtreeInvalid(); | 194 recursionData.setWholeSubtreeInvalid(); |
| 130 return false; | 195 return false; |
| 131 } | 196 } |
| 197 |
| 132 bool thisElementNeedsStyleRecalc = recursionData.matchesCurrentInvalidationS
ets(element); | 198 bool thisElementNeedsStyleRecalc = recursionData.matchesCurrentInvalidationS
ets(element); |
| 133 if (element.needsStyleInvalidation()) { | 199 thisElementNeedsStyleRecalc |= siblingData.matchCurrentInvalidationSets(elem
ent, recursionData); |
| 134 if (InvalidationList* invalidationList = m_pendingInvalidationMap.get(&e
lement)) { | 200 |
| 135 for (const auto& invalidationSet : *invalidationList) | 201 if (UNLIKELY(element.needsStyleInvalidation())) { |
| 202 PendingInvalidations* pendingInvalidations = m_pendingInvalidationMap.ge
t(&element); |
| 203 ASSERT(pendingInvalidations); |
| 204 |
| 205 for (const auto& invalidationSet : pendingInvalidations->siblings()) |
| 206 siblingData.pushInvalidationSet(*invalidationSet); |
| 207 |
| 208 if (!pendingInvalidations->descendants().isEmpty()) { |
| 209 for (const auto& invalidationSet : pendingInvalidations->descendants
()) |
| 136 recursionData.pushInvalidationSet(*invalidationSet); | 210 recursionData.pushInvalidationSet(*invalidationSet); |
| 137 if (UNLIKELY(*s_tracingEnabled)) { | 211 if (UNLIKELY(*s_tracingEnabled)) { |
| 138 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timelin
e.invalidationTracking"), | 212 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timelin
e.invalidationTracking"), |
| 139 "StyleInvalidatorInvalidationTracking", | 213 "StyleInvalidatorInvalidationTracking", |
| 140 TRACE_EVENT_SCOPE_THREAD, | 214 TRACE_EVENT_SCOPE_THREAD, |
| 141 "data", InspectorStyleInvalidatorInvalidateEvent::invalidati
onList(element, *invalidationList)); | 215 "data", InspectorStyleInvalidatorInvalidateEvent::invalidati
onList(element, pendingInvalidations->descendants())); |
| 142 } | 216 } |
| 143 } | 217 } |
| 144 } | 218 } |
| 145 return thisElementNeedsStyleRecalc; | 219 return thisElementNeedsStyleRecalc; |
| 146 } | 220 } |
| 147 | 221 |
| 148 bool StyleInvalidator::invalidateChildren(Element& element, StyleInvalidator::Re
cursionData& recursionData) | 222 bool StyleInvalidator::invalidateChildren(Element& element, RecursionData& recur
sionData) |
| 149 { | 223 { |
| 224 SiblingData siblingData; |
| 150 bool someChildrenNeedStyleRecalc = false; | 225 bool someChildrenNeedStyleRecalc = false; |
| 151 for (ShadowRoot* root = element.youngestShadowRoot(); root; root = root->old
erShadowRoot()) { | 226 for (ShadowRoot* root = element.youngestShadowRoot(); root; root = root->old
erShadowRoot()) { |
| 152 if (!recursionData.treeBoundaryCrossing() && !root->childNeedsStyleInval
idation() && !root->needsStyleInvalidation()) | 227 if (!recursionData.treeBoundaryCrossing() && !root->childNeedsStyleInval
idation() && !root->needsStyleInvalidation()) |
| 153 continue; | 228 continue; |
| 154 for (Element* child = ElementTraversal::firstChild(*root); child; child
= ElementTraversal::nextSibling(*child)) { | 229 for (Element* child = ElementTraversal::firstChild(*root); child; child
= ElementTraversal::nextSibling(*child)) { |
| 155 bool childRecalced = invalidate(*child, recursionData); | 230 bool childRecalced = invalidate(*child, recursionData, siblingData); |
| 156 someChildrenNeedStyleRecalc = someChildrenNeedStyleRecalc || childRe
calced; | 231 someChildrenNeedStyleRecalc = someChildrenNeedStyleRecalc || childRe
calced; |
| 157 } | 232 } |
| 158 root->clearChildNeedsStyleInvalidation(); | 233 root->clearChildNeedsStyleInvalidation(); |
| 159 root->clearNeedsStyleInvalidation(); | 234 root->clearNeedsStyleInvalidation(); |
| 160 } | 235 } |
| 161 for (Element* child = ElementTraversal::firstChild(element); child; child =
ElementTraversal::nextSibling(*child)) { | 236 for (Element* child = ElementTraversal::firstChild(element); child; child =
ElementTraversal::nextSibling(*child)) { |
| 162 bool childRecalced = invalidate(*child, recursionData); | 237 bool childRecalced = invalidate(*child, recursionData, siblingData); |
| 163 someChildrenNeedStyleRecalc = someChildrenNeedStyleRecalc || childRecalc
ed; | 238 someChildrenNeedStyleRecalc = someChildrenNeedStyleRecalc || childRecalc
ed; |
| 164 } | 239 } |
| 165 return someChildrenNeedStyleRecalc; | 240 return someChildrenNeedStyleRecalc; |
| 166 } | 241 } |
| 167 | 242 |
| 168 bool StyleInvalidator::invalidate(Element& element, StyleInvalidator::RecursionD
ata& recursionData) | 243 bool StyleInvalidator::invalidate(Element& element, RecursionData& recursionData
, SiblingData& siblingData) |
| 169 { | 244 { |
| 170 RecursionCheckpoint checkpoint(&recursionData); | 245 RecursionCheckpoint checkpoint(&recursionData); |
| 246 siblingData.advance(); |
| 171 | 247 |
| 172 bool thisElementNeedsStyleRecalc = checkInvalidationSetsAgainstElement(eleme
nt, recursionData); | 248 bool thisElementNeedsStyleRecalc = checkInvalidationSetsAgainstElement(eleme
nt, recursionData, siblingData); |
| 173 | 249 |
| 174 bool someChildrenNeedStyleRecalc = false; | 250 bool someChildrenNeedStyleRecalc = false; |
| 175 if (recursionData.hasInvalidationSets() || element.childNeedsStyleInvalidati
on()) | 251 if (recursionData.hasInvalidationSets() || element.childNeedsStyleInvalidati
on()) |
| 176 someChildrenNeedStyleRecalc = invalidateChildren(element, recursionData)
; | 252 someChildrenNeedStyleRecalc = invalidateChildren(element, recursionData)
; |
| 177 | 253 |
| 178 if (thisElementNeedsStyleRecalc) { | 254 if (thisElementNeedsStyleRecalc) { |
| 179 ASSERT(!recursionData.wholeSubtreeInvalid()); | 255 ASSERT(!recursionData.wholeSubtreeInvalid()); |
| 180 element.setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracin
g::create(StyleChangeReason::StyleInvalidator)); | 256 element.setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracin
g::create(StyleChangeReason::StyleInvalidator)); |
| 181 } else if (recursionData.hasInvalidationSets() && someChildrenNeedStyleRecal
c) { | 257 } else if (recursionData.hasInvalidationSets() && someChildrenNeedStyleRecal
c) { |
| 182 // Clone the ComputedStyle in order to preserve correct style sharing, i
f possible. Otherwise recalc style. | 258 // Clone the ComputedStyle in order to preserve correct style sharing, i
f possible. Otherwise recalc style. |
| (...skipping 15 matching lines...) Expand all Loading... |
| 198 } | 274 } |
| 199 | 275 |
| 200 DEFINE_TRACE(StyleInvalidator) | 276 DEFINE_TRACE(StyleInvalidator) |
| 201 { | 277 { |
| 202 #if ENABLE(OILPAN) | 278 #if ENABLE(OILPAN) |
| 203 visitor->trace(m_pendingInvalidationMap); | 279 visitor->trace(m_pendingInvalidationMap); |
| 204 #endif | 280 #endif |
| 205 } | 281 } |
| 206 | 282 |
| 207 } // namespace blink | 283 } // namespace blink |
| OLD | NEW |