| 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/DescendantInvalidationSet.h" | 10 #include "core/css/invalidation/DescendantInvalidationSet.h" |
| (...skipping 15 matching lines...) Expand all Loading... |
| 26 // with DescendantInvalidationSet to avoid additional GOT lookup cost. | 26 // with DescendantInvalidationSet 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 clearPendingInvalidations(); |
| 41 } | 42 } |
| 42 | 43 |
| 43 void StyleInvalidator::scheduleInvalidation(PassRefPtrWillBeRawPtr<DescendantInv
alidationSet> invalidationSet, Element& element) | 44 void StyleInvalidator::scheduleInvalidation(PassRefPtrWillBeRawPtr<DescendantInv
alidationSet> invalidationSet, Element& element, InvalidateType type) |
| 44 { | 45 { |
| 45 ASSERT(element.inActiveDocument()); | 46 ASSERT(element.inActiveDocument()); |
| 46 if (element.styleChangeType() >= SubtreeStyleChange) | 47 if (type == InvalidateDescendants) { |
| 47 return; | 48 if (element.styleChangeType() >= SubtreeStyleChange) |
| 48 if (invalidationSet->wholeSubtreeInvalid()) { | 49 return; |
| 49 element.setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTrac
ing::create(StyleChangeReason::StyleInvalidator)); | 50 if (invalidationSet->wholeSubtreeInvalid()) { |
| 50 clearInvalidation(element); | 51 element.setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonFor
Tracing::create(StyleChangeReason::StyleInvalidator)); |
| 51 return; | 52 clearInvalidation(element); |
| 53 return; |
| 54 } |
| 55 if (invalidationSet->isEmpty()) { |
| 56 element.setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTr
acing::create(StyleChangeReason::StyleInvalidator)); |
| 57 return; |
| 58 } |
| 59 element.setNeedsStyleInvalidation(); |
| 60 } else { |
| 61 element.markAncestorsWithChildNeedsStyleInvalidation(); |
| 52 } | 62 } |
| 53 if (invalidationSet->isEmpty()) { | 63 InvalidationList& list = ensurePendingInvalidationList(element, type); |
| 54 element.setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracin
g::create(StyleChangeReason::StyleInvalidator)); | |
| 55 return; | |
| 56 } | |
| 57 | |
| 58 InvalidationList& list = ensurePendingInvalidationList(element); | |
| 59 list.append(invalidationSet); | 64 list.append(invalidationSet); |
| 60 element.setNeedsStyleInvalidation(); | |
| 61 } | 65 } |
| 62 | 66 |
| 63 StyleInvalidator::InvalidationList& StyleInvalidator::ensurePendingInvalidationL
ist(Element& element) | 67 StyleInvalidator::InvalidationList& StyleInvalidator::ensurePendingInvalidationL
ist(Element& element, InvalidateType type) |
| 64 { | 68 { |
| 65 PendingInvalidationMap::AddResult addResult = m_pendingInvalidationMap.add(&
element, nullptr); | 69 PendingInvalidationMap::AddResult addResult = m_pendingInvalidationMap[type]
.add(&element, nullptr); |
| 66 if (addResult.isNewEntry) | 70 if (addResult.isNewEntry) |
| 67 addResult.storedValue->value = adoptPtrWillBeNoop(new InvalidationList); | 71 addResult.storedValue->value = adoptPtrWillBeNoop(new InvalidationList); |
| 68 return *addResult.storedValue->value; | 72 return *addResult.storedValue->value; |
| 69 } | 73 } |
| 70 | 74 |
| 71 void StyleInvalidator::clearInvalidation(Element& element) | 75 void StyleInvalidator::clearInvalidation(Element& element) |
| 72 { | 76 { |
| 73 if (!element.needsStyleInvalidation()) | 77 if (!element.needsStyleInvalidation()) |
| 74 return; | 78 return; |
| 75 m_pendingInvalidationMap.remove(&element); | 79 m_pendingInvalidationMap[InvalidateDescendants].remove(&element); |
| 80 m_pendingInvalidationMap[InvalidateSiblings].remove(&element); |
| 76 element.clearNeedsStyleInvalidation(); | 81 element.clearNeedsStyleInvalidation(); |
| 77 } | 82 } |
| 78 | 83 |
| 79 void StyleInvalidator::clearPendingInvalidations() | 84 void StyleInvalidator::clearPendingInvalidations() |
| 80 { | 85 { |
| 81 m_pendingInvalidationMap.clear(); | 86 m_pendingInvalidationMap[InvalidateDescendants].clear(); |
| 87 m_pendingInvalidationMap[InvalidateSiblings].clear(); |
| 82 } | 88 } |
| 83 | 89 |
| 84 StyleInvalidator::StyleInvalidator() | 90 StyleInvalidator::StyleInvalidator() |
| 85 { | 91 { |
| 86 s_tracingEnabled = TRACE_EVENT_API_GET_CATEGORY_ENABLED(TRACE_DISABLED_BY_DE
FAULT("devtools.timeline.invalidationTracking")); | 92 s_tracingEnabled = TRACE_EVENT_API_GET_CATEGORY_ENABLED(TRACE_DISABLED_BY_DE
FAULT("devtools.timeline.invalidationTracking")); |
| 87 DescendantInvalidationSet::cacheTracingFlag(); | 93 DescendantInvalidationSet::cacheTracingFlag(); |
| 88 } | 94 } |
| 89 | 95 |
| 90 StyleInvalidator::~StyleInvalidator() | 96 StyleInvalidator::~StyleInvalidator() |
| 91 { | 97 { |
| 92 } | 98 } |
| 93 | 99 |
| 94 void StyleInvalidator::RecursionData::pushInvalidationSet(const DescendantInvali
dationSet& invalidationSet) | 100 void StyleInvalidator::RecursionData::pushInvalidationSet(const DescendantInvali
dationSet& invalidationSet) |
| 95 { | 101 { |
| 96 ASSERT(!m_wholeSubtreeInvalid); | 102 ASSERT(!m_wholeSubtreeInvalid); |
| 97 ASSERT(!invalidationSet.wholeSubtreeInvalid()); | 103 ASSERT(!invalidationSet.wholeSubtreeInvalid()); |
| 98 ASSERT(!invalidationSet.isEmpty()); | 104 ASSERT(!invalidationSet.isEmpty()); |
| 99 if (invalidationSet.treeBoundaryCrossing()) | 105 if (invalidationSet.treeBoundaryCrossing()) |
| 100 m_treeBoundaryCrossing = true; | 106 m_treeBoundaryCrossing = true; |
| 101 if (invalidationSet.insertionPointCrossing()) | 107 if (invalidationSet.insertionPointCrossing()) |
| 102 m_insertionPointCrossing = true; | 108 m_insertionPointCrossing = true; |
| 103 m_invalidationSets.append(&invalidationSet); | 109 m_invalidationSets.append(&invalidationSet); |
| 104 m_invalidateCustomPseudo = invalidationSet.customPseudoInvalid(); | 110 m_invalidateCustomPseudo = invalidationSet.customPseudoInvalid(); |
| 105 } | 111 } |
| 106 | 112 |
| 107 ALWAYS_INLINE bool StyleInvalidator::RecursionData::matchesCurrentInvalidationSe
ts(Element& element) | 113 ALWAYS_INLINE bool StyleInvalidator::RecursionData::matchesCurrentInvalidationSe
ts(Element& element) const |
| 108 { | 114 { |
| 109 if (m_invalidateCustomPseudo && element.shadowPseudoId() != nullAtom) { | 115 if (m_invalidateCustomPseudo && element.shadowPseudoId() != nullAtom) { |
| 110 TRACE_STYLE_INVALIDATOR_INVALIDATION_IF_ENABLED(element, InvalidateCusto
mPseudo); | 116 TRACE_STYLE_INVALIDATOR_INVALIDATION_IF_ENABLED(element, InvalidateCusto
mPseudo); |
| 111 return true; | 117 return true; |
| 112 } | 118 } |
| 113 | 119 |
| 114 if (m_insertionPointCrossing && element.isInsertionPoint()) | 120 if (m_insertionPointCrossing && element.isInsertionPoint()) |
| 115 return true; | 121 return true; |
| 116 | 122 |
| 117 for (const auto& invalidationSet : m_invalidationSets) { | 123 for (const auto& invalidationSet : m_invalidationSets) { |
| 118 if (invalidationSet->invalidatesElement(element)) | 124 if (invalidationSet->invalidatesElement(element)) |
| 119 return true; | 125 return true; |
| 120 } | 126 } |
| 121 | 127 |
| 122 return false; | 128 return false; |
| 123 } | 129 } |
| 124 | 130 |
| 131 void StyleInvalidator::SiblingData::pushInvalidationSet(const DescendantInvalida
tionSet& invalidationSet) |
| 132 { |
| 133 m_invalidationSets.append(&invalidationSet); |
| 134 if (invalidationSet.maxDirectAdjacentSelectors() == std::numeric_limits<unsi
gned>::max()) |
| 135 m_invalidationLimits.append(std::numeric_limits<unsigned>::max()); |
| 136 else |
| 137 m_invalidationLimits.append(m_elementIndex + invalidationSet.maxDirectAd
jacentSelectors()); |
| 138 } |
| 139 |
| 140 ALWAYS_INLINE bool StyleInvalidator::SiblingData::matchesCurrentInvalidationSets
(Element& element) |
| 141 { |
| 142 m_elementIndex++; |
| 143 |
| 144 for (unsigned index = 0; index < m_invalidationLimits.size(); ++index) { |
| 145 if (m_elementIndex > m_invalidationLimits[index]) |
| 146 continue; |
| 147 |
| 148 if (m_invalidationSets[index]->wholeSubtreeInvalid() || m_invalidationSe
ts[index]->invalidatesElement(element)) |
| 149 return true; |
| 150 } |
| 151 |
| 152 return false; |
| 153 } |
| 154 |
| 125 ALWAYS_INLINE bool StyleInvalidator::checkInvalidationSetsAgainstElement(Element
& element, StyleInvalidator::RecursionData& recursionData) | 155 ALWAYS_INLINE bool StyleInvalidator::checkInvalidationSetsAgainstElement(Element
& element, StyleInvalidator::RecursionData& recursionData) |
| 126 { | 156 { |
| 127 if (element.styleChangeType() >= SubtreeStyleChange || recursionData.wholeSu
btreeInvalid()) { | 157 if (element.styleChangeType() >= SubtreeStyleChange || recursionData.wholeSu
btreeInvalid()) { |
| 128 recursionData.setWholeSubtreeInvalid(); | 158 recursionData.setWholeSubtreeInvalid(); |
| 129 return false; | 159 return false; |
| 130 } | 160 } |
| 131 if (element.needsStyleInvalidation()) { | 161 if (element.needsStyleInvalidation()) { |
| 132 if (InvalidationList* invalidationList = m_pendingInvalidationMap.get(&e
lement)) { | 162 if (InvalidationList* invalidationList = m_pendingInvalidationMap[Invali
dateDescendants].get(&element)) { |
| 133 for (const auto& invalidationSet : *invalidationList) | 163 for (const auto& invalidationSet : *invalidationList) |
| 134 recursionData.pushInvalidationSet(*invalidationSet); | 164 recursionData.pushInvalidationSet(*invalidationSet); |
| 135 if (UNLIKELY(*s_tracingEnabled)) { | 165 if (UNLIKELY(*s_tracingEnabled)) { |
| 136 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timelin
e.invalidationTracking"), | 166 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timelin
e.invalidationTracking"), |
| 137 "StyleInvalidatorInvalidationTracking", | 167 "StyleInvalidatorInvalidationTracking", |
| 138 TRACE_EVENT_SCOPE_THREAD, | 168 TRACE_EVENT_SCOPE_THREAD, |
| 139 "data", InspectorStyleInvalidatorInvalidateEvent::invalidati
onList(element, *invalidationList)); | 169 "data", InspectorStyleInvalidatorInvalidateEvent::invalidati
onList(element, *invalidationList)); |
| 140 } | 170 } |
| 141 return true; | 171 return true; |
| 142 } | 172 } |
| 143 } | 173 } |
| 144 | 174 |
| 145 return recursionData.matchesCurrentInvalidationSets(element); | 175 return recursionData.matchesCurrentInvalidationSets(element); |
| 146 } | 176 } |
| 147 | 177 |
| 148 bool StyleInvalidator::invalidateChildren(Element& element, StyleInvalidator::Re
cursionData& recursionData) | 178 bool StyleInvalidator::invalidateChildren(Element& element, StyleInvalidator::Re
cursionData& recursionData) |
| 149 { | 179 { |
| 180 SiblingData siblingData; |
| 181 |
| 150 bool someChildrenNeedStyleRecalc = false; | 182 bool someChildrenNeedStyleRecalc = false; |
| 151 for (ShadowRoot* root = element.youngestShadowRoot(); root; root = root->old
erShadowRoot()) { | 183 for (ShadowRoot* root = element.youngestShadowRoot(); root; root = root->old
erShadowRoot()) { |
| 152 if (!recursionData.treeBoundaryCrossing() && !root->childNeedsStyleInval
idation() && !root->needsStyleInvalidation()) | 184 if (!recursionData.treeBoundaryCrossing() && !root->childNeedsStyleInval
idation() && !root->needsStyleInvalidation()) |
| 153 continue; | 185 continue; |
| 154 for (Element* child = ElementTraversal::firstChild(*root); child; child
= ElementTraversal::nextSibling(*child)) { | 186 for (Element* child = ElementTraversal::firstChild(*root); child; child
= ElementTraversal::nextSibling(*child)) { |
| 155 bool childRecalced = invalidate(*child, recursionData); | 187 bool childRecalced = invalidate(*child, recursionData, siblingData); |
| 156 someChildrenNeedStyleRecalc = someChildrenNeedStyleRecalc || childRe
calced; | 188 someChildrenNeedStyleRecalc = someChildrenNeedStyleRecalc || childRe
calced; |
| 157 } | 189 } |
| 158 root->clearChildNeedsStyleInvalidation(); | 190 root->clearChildNeedsStyleInvalidation(); |
| 159 root->clearNeedsStyleInvalidation(); | 191 root->clearNeedsStyleInvalidation(); |
| 160 } | 192 } |
| 161 for (Element* child = ElementTraversal::firstChild(element); child; child =
ElementTraversal::nextSibling(*child)) { | 193 for (Element* child = ElementTraversal::firstChild(element); child; child =
ElementTraversal::nextSibling(*child)) { |
| 162 bool childRecalced = invalidate(*child, recursionData); | 194 bool childRecalced = invalidate(*child, recursionData, siblingData); |
| 163 someChildrenNeedStyleRecalc = someChildrenNeedStyleRecalc || childRecalc
ed; | 195 someChildrenNeedStyleRecalc = someChildrenNeedStyleRecalc || childRecalc
ed; |
| 164 } | 196 } |
| 165 return someChildrenNeedStyleRecalc; | 197 return someChildrenNeedStyleRecalc; |
| 166 } | 198 } |
| 167 | 199 |
| 168 bool StyleInvalidator::invalidate(Element& element, StyleInvalidator::RecursionD
ata& recursionData) | 200 bool StyleInvalidator::invalidate(Element& element, StyleInvalidator::RecursionD
ata& recursionData, SiblingData& siblingData) |
| 169 { | 201 { |
| 170 RecursionCheckpoint checkpoint(&recursionData); | 202 RecursionCheckpoint checkpoint(&recursionData); |
| 171 | 203 |
| 204 if (siblingData.matchesCurrentInvalidationSets(element)) { |
| 205 element.setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTrac
ing::create(StyleChangeReason::StyleInvalidator)); |
| 206 } |
| 207 |
| 172 bool thisElementNeedsStyleRecalc = checkInvalidationSetsAgainstElement(eleme
nt, recursionData); | 208 bool thisElementNeedsStyleRecalc = checkInvalidationSetsAgainstElement(eleme
nt, recursionData); |
| 173 | 209 |
| 174 bool someChildrenNeedStyleRecalc = false; | 210 bool someChildrenNeedStyleRecalc = false; |
| 175 if (recursionData.hasInvalidationSets() || element.childNeedsStyleInvalidati
on()) | 211 if (recursionData.hasInvalidationSets() || element.childNeedsStyleInvalidati
on()) |
| 176 someChildrenNeedStyleRecalc = invalidateChildren(element, recursionData)
; | 212 someChildrenNeedStyleRecalc = invalidateChildren(element, recursionData)
; |
| 177 | 213 |
| 178 if (thisElementNeedsStyleRecalc) { | 214 if (thisElementNeedsStyleRecalc) { |
| 179 ASSERT(!recursionData.wholeSubtreeInvalid()); | 215 ASSERT(!recursionData.wholeSubtreeInvalid()); |
| 180 element.setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracin
g::create(StyleChangeReason::StyleInvalidator)); | 216 element.setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracin
g::create(StyleChangeReason::StyleInvalidator)); |
| 181 } else if (recursionData.hasInvalidationSets() && someChildrenNeedStyleRecal
c) { | 217 } else if (recursionData.hasInvalidationSets() && someChildrenNeedStyleRecal
c) { |
| 182 // Clone the ComputedStyle in order to preserve correct style sharing, i
f possible. Otherwise recalc style. | 218 // Clone the ComputedStyle in order to preserve correct style sharing, i
f possible. Otherwise recalc style. |
| 183 if (LayoutObject* layoutObject = element.layoutObject()) { | 219 if (LayoutObject* layoutObject = element.layoutObject()) { |
| 184 layoutObject->setStyleInternal(ComputedStyle::clone(layoutObject->st
yleRef())); | 220 layoutObject->setStyleInternal(ComputedStyle::clone(layoutObject->st
yleRef())); |
| 185 } else { | 221 } else { |
| 186 TRACE_STYLE_INVALIDATOR_INVALIDATION_IF_ENABLED(element, PreventStyl
eSharingForParent); | 222 TRACE_STYLE_INVALIDATOR_INVALIDATION_IF_ENABLED(element, PreventStyl
eSharingForParent); |
| 187 element.setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTr
acing::create(StyleChangeReason::StyleInvalidator)); | 223 element.setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTr
acing::create(StyleChangeReason::StyleInvalidator)); |
| 188 } | 224 } |
| 189 } | 225 } |
| 190 | 226 |
| 191 if (recursionData.insertionPointCrossing() && element.isInsertionPoint()) | 227 if (recursionData.insertionPointCrossing() && element.isInsertionPoint()) |
| 192 element.setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTrac
ing::create(StyleChangeReason::StyleInvalidator)); | 228 element.setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTrac
ing::create(StyleChangeReason::StyleInvalidator)); |
| 193 | 229 |
| 194 element.clearChildNeedsStyleInvalidation(); | 230 element.clearChildNeedsStyleInvalidation(); |
| 195 element.clearNeedsStyleInvalidation(); | 231 element.clearNeedsStyleInvalidation(); |
| 196 | 232 |
| 233 if (InvalidationList* invalidationList = m_pendingInvalidationMap[Invalidate
Siblings].get(&element)) { |
| 234 for (const auto& invalidationSet : *invalidationList) { |
| 235 siblingData.pushInvalidationSet(*invalidationSet); |
| 236 } |
| 237 } |
| 238 |
| 197 return thisElementNeedsStyleRecalc; | 239 return thisElementNeedsStyleRecalc; |
| 198 } | 240 } |
| 199 | 241 |
| 200 DEFINE_TRACE(StyleInvalidator) | 242 DEFINE_TRACE(StyleInvalidator) |
| 201 { | 243 { |
| 202 #if ENABLE(OILPAN) | 244 #if ENABLE(OILPAN) |
| 203 visitor->trace(m_pendingInvalidationMap); | 245 visitor->trace(m_pendingInvalidationMap[InvalidateDescendants]); |
| 246 visitor->trace(m_pendingInvalidationMap[InvalidateSiblings]); |
| 204 #endif | 247 #endif |
| 205 } | 248 } |
| 206 | 249 |
| 207 } // namespace blink | 250 } // namespace blink |
| OLD | NEW |