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::scheduleInvalidationSetsForElement(const InvalidationSetV
ector& descendant, const InvalidationSetVector& sibling, Element& element) |
44 { | 45 { |
45 ASSERT(element.inActiveDocument()); | 46 ASSERT(element.inActiveDocument()); |
46 if (element.styleChangeType() >= SubtreeStyleChange) | 47 |
47 return; | 48 bool requiresDescendantInvalidation = false; |
48 if (invalidationSet->wholeSubtreeInvalid()) { | 49 if (element.styleChangeType() < SubtreeStyleChange) { |
49 element.setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTrac
ing::create(StyleChangeReason::StyleInvalidator)); | 50 for (auto& invalidationSet : descendant) { |
50 clearInvalidation(element); | 51 if (invalidationSet->wholeSubtreeInvalid()) { |
51 return; | 52 element.setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReaso
nForTracing::create(StyleChangeReason::StyleInvalidator)); |
52 } | 53 requiresDescendantInvalidation = false; |
53 if (invalidationSet->isEmpty()) { | 54 break; |
54 element.setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracin
g::create(StyleChangeReason::StyleInvalidator)); | 55 } |
55 return; | 56 if (invalidationSet->isEmpty()) { |
| 57 element.setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonF
orTracing::create(StyleChangeReason::StyleInvalidator)); |
| 58 } else { |
| 59 requiresDescendantInvalidation = true; |
| 60 } |
| 61 } |
56 } | 62 } |
57 | 63 |
58 InvalidationList& list = ensurePendingInvalidationList(element); | 64 if (sibling.isEmpty() && !requiresDescendantInvalidation) |
59 list.append(invalidationSet); | 65 return; |
| 66 |
60 element.setNeedsStyleInvalidation(); | 67 element.setNeedsStyleInvalidation(); |
61 } | 68 InvalidationListData& listData = ensurePendingInvalidationListData(element); |
62 | 69 |
63 StyleInvalidator::InvalidationList& StyleInvalidator::ensurePendingInvalidationL
ist(Element& element) | 70 for (auto& invalidationSet : sibling) |
64 { | 71 listData.siblings().append(invalidationSet); |
65 PendingInvalidationMap::AddResult addResult = m_pendingInvalidationMap.add(&
element, nullptr); | 72 |
66 if (addResult.isNewEntry) | 73 if (!requiresDescendantInvalidation) |
67 addResult.storedValue->value = adoptPtrWillBeNoop(new InvalidationList); | 74 return; |
68 return *addResult.storedValue->value; | 75 |
| 76 for (auto& invalidationSet : descendant) { |
| 77 ASSERT(!invalidationSet->wholeSubtreeInvalid()); |
| 78 if (!invalidationSet->isEmpty()) |
| 79 listData.descendants().append(invalidationSet); |
| 80 } |
69 } | 81 } |
70 | 82 |
71 void StyleInvalidator::clearInvalidation(Element& element) | 83 void StyleInvalidator::clearInvalidation(Element& element) |
72 { | 84 { |
73 if (!element.needsStyleInvalidation()) | 85 if (!element.needsStyleInvalidation()) |
74 return; | 86 return; |
75 m_pendingInvalidationMap.remove(&element); | 87 m_pendingInvalidationMap.remove(&element); |
76 element.clearNeedsStyleInvalidation(); | 88 } |
| 89 |
| 90 InvalidationListData& StyleInvalidator::ensurePendingInvalidationListData(Elemen
t& element) |
| 91 { |
| 92 PendingInvalidationMap::AddResult addResult = m_pendingInvalidationMap.add(&
element, nullptr); |
| 93 if (addResult.isNewEntry) |
| 94 addResult.storedValue->value = InvalidationListData::create(); |
| 95 return *addResult.storedValue->value; |
77 } | 96 } |
78 | 97 |
79 void StyleInvalidator::clearPendingInvalidations() | 98 void StyleInvalidator::clearPendingInvalidations() |
80 { | 99 { |
81 m_pendingInvalidationMap.clear(); | 100 m_pendingInvalidationMap.clear(); |
82 } | 101 } |
83 | 102 |
84 StyleInvalidator::StyleInvalidator() | 103 StyleInvalidator::StyleInvalidator() |
85 { | 104 { |
86 s_tracingEnabled = TRACE_EVENT_API_GET_CATEGORY_ENABLED(TRACE_DISABLED_BY_DE
FAULT("devtools.timeline.invalidationTracking")); | 105 s_tracingEnabled = TRACE_EVENT_API_GET_CATEGORY_ENABLED(TRACE_DISABLED_BY_DE
FAULT("devtools.timeline.invalidationTracking")); |
(...skipping 10 matching lines...) Expand all Loading... |
97 ASSERT(!invalidationSet.wholeSubtreeInvalid()); | 116 ASSERT(!invalidationSet.wholeSubtreeInvalid()); |
98 ASSERT(!invalidationSet.isEmpty()); | 117 ASSERT(!invalidationSet.isEmpty()); |
99 if (invalidationSet.treeBoundaryCrossing()) | 118 if (invalidationSet.treeBoundaryCrossing()) |
100 m_treeBoundaryCrossing = true; | 119 m_treeBoundaryCrossing = true; |
101 if (invalidationSet.insertionPointCrossing()) | 120 if (invalidationSet.insertionPointCrossing()) |
102 m_insertionPointCrossing = true; | 121 m_insertionPointCrossing = true; |
103 m_invalidationSets.append(&invalidationSet); | 122 m_invalidationSets.append(&invalidationSet); |
104 m_invalidateCustomPseudo = invalidationSet.customPseudoInvalid(); | 123 m_invalidateCustomPseudo = invalidationSet.customPseudoInvalid(); |
105 } | 124 } |
106 | 125 |
107 ALWAYS_INLINE bool StyleInvalidator::RecursionData::matchesCurrentInvalidationSe
ts(Element& element) | 126 ALWAYS_INLINE bool StyleInvalidator::RecursionData::matchesCurrentInvalidationSe
ts(Element& element) const |
108 { | 127 { |
109 if (m_invalidateCustomPseudo && element.shadowPseudoId() != nullAtom) { | 128 if (m_invalidateCustomPseudo && element.shadowPseudoId() != nullAtom) { |
110 TRACE_STYLE_INVALIDATOR_INVALIDATION_IF_ENABLED(element, InvalidateCusto
mPseudo); | 129 TRACE_STYLE_INVALIDATOR_INVALIDATION_IF_ENABLED(element, InvalidateCusto
mPseudo); |
111 return true; | 130 return true; |
112 } | 131 } |
113 | 132 |
114 if (m_insertionPointCrossing && element.isInsertionPoint()) | 133 if (m_insertionPointCrossing && element.isInsertionPoint()) |
115 return true; | 134 return true; |
116 | 135 |
117 for (const auto& invalidationSet : m_invalidationSets) { | 136 for (const auto& invalidationSet : m_invalidationSets) { |
118 if (invalidationSet->invalidatesElement(element)) | 137 if (invalidationSet->invalidatesElement(element)) |
119 return true; | 138 return true; |
120 } | 139 } |
121 | 140 |
122 return false; | 141 return false; |
123 } | 142 } |
124 | 143 |
125 ALWAYS_INLINE bool StyleInvalidator::checkInvalidationSetsAgainstElement(Element
& element, StyleInvalidator::RecursionData& recursionData) | 144 void StyleInvalidator::SiblingData::pushInvalidationSet(const DescendantInvalida
tionSet& invalidationSet) |
| 145 { |
| 146 unsigned invalidationLimit; |
| 147 if (invalidationSet.maxDirectAdjacentSelectors() == std::numeric_limits<unsi
gned>::max()) |
| 148 invalidationLimit = std::numeric_limits<unsigned>::max(); |
| 149 else |
| 150 invalidationLimit = m_elementIndex + invalidationSet.maxDirectAdjacentSe
lectors(); |
| 151 m_invalidationEntries.append(Entry { &invalidationSet, invalidationLimit }); |
| 152 } |
| 153 |
| 154 ALWAYS_INLINE bool StyleInvalidator::SiblingData::matchCurrentInvalidationSets(E
lement& element, RecursionData& recursionData, bool thisElementNeedsStyleRecalc) |
| 155 { |
| 156 ASSERT(!recursionData.wholeSubtreeInvalid()); |
| 157 |
| 158 unsigned index = 0; |
| 159 while (index < m_invalidationEntries.size()) { |
| 160 if (m_elementIndex > m_invalidationEntries[index].invalidationLimit) { |
| 161 m_invalidationEntries[index] = m_invalidationEntries[m_invalidationE
ntries.size() - 1]; |
| 162 m_invalidationEntries.removeLast(); |
| 163 continue; |
| 164 } |
| 165 |
| 166 const DescendantInvalidationSet* invalidationSet = m_invalidationEntries
[index].invalidationSet.get(); |
| 167 |
| 168 if (invalidationSet->wholeSubtreeInvalid()) { |
| 169 element.setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonFor
Tracing::create(StyleChangeReason::StyleInvalidator)); |
| 170 recursionData.setWholeSubtreeInvalid(); |
| 171 return false; |
| 172 } |
| 173 |
| 174 if (invalidationSet->invalidatesElement(element)) { |
| 175 ASSERT(invalidationSet->siblingInvalid() || invalidationSet->descend
ants()); |
| 176 if (invalidationSet->siblingInvalid()) |
| 177 thisElementNeedsStyleRecalc = true; |
| 178 if (invalidationSet->descendants()) |
| 179 recursionData.pushInvalidationSet(*invalidationSet->descendants(
)); |
| 180 } |
| 181 |
| 182 ++index; |
| 183 } |
| 184 return thisElementNeedsStyleRecalc; |
| 185 } |
| 186 |
| 187 ALWAYS_INLINE bool StyleInvalidator::checkInvalidationSetsAgainstElement(Element
& element, RecursionData& recursionData, SiblingData& siblingData) |
126 { | 188 { |
127 if (element.styleChangeType() >= SubtreeStyleChange || recursionData.wholeSu
btreeInvalid()) { | 189 if (element.styleChangeType() >= SubtreeStyleChange || recursionData.wholeSu
btreeInvalid()) { |
128 recursionData.setWholeSubtreeInvalid(); | 190 recursionData.setWholeSubtreeInvalid(); |
129 return false; | 191 return false; |
130 } | 192 } |
131 if (element.needsStyleInvalidation()) { | 193 |
132 if (InvalidationList* invalidationList = m_pendingInvalidationMap.get(&e
lement)) { | 194 bool thisElementNeedsStyleRecalc = false; |
133 for (const auto& invalidationSet : *invalidationList) | 195 if (UNLIKELY(element.needsStyleInvalidation())) { |
| 196 RefPtrWillBeRawPtr<InvalidationListData> listData = m_pendingInvalidatio
nMap.get(&element); |
| 197 ASSERT(listData); |
| 198 |
| 199 if (listData->descendants().isEmpty()) { |
| 200 thisElementNeedsStyleRecalc = recursionData.matchesCurrentInvalidati
onSets(element); |
| 201 } else { |
| 202 for (const auto& invalidationSet : listData->descendants()) |
134 recursionData.pushInvalidationSet(*invalidationSet); | 203 recursionData.pushInvalidationSet(*invalidationSet); |
135 if (UNLIKELY(*s_tracingEnabled)) { | 204 if (UNLIKELY(*s_tracingEnabled)) { |
136 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timelin
e.invalidationTracking"), | 205 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timelin
e.invalidationTracking"), |
137 "StyleInvalidatorInvalidationTracking", | 206 "StyleInvalidatorInvalidationTracking", |
138 TRACE_EVENT_SCOPE_THREAD, | 207 TRACE_EVENT_SCOPE_THREAD, |
139 "data", InspectorStyleInvalidatorInvalidateEvent::invalidati
onList(element, *invalidationList)); | 208 "data", InspectorStyleInvalidatorInvalidateEvent::invalidati
onList(element, listData->descendants())); |
140 } | 209 } |
141 return true; | 210 thisElementNeedsStyleRecalc = true; |
142 } | 211 } |
| 212 thisElementNeedsStyleRecalc = siblingData.matchCurrentInvalidationSets(e
lement, recursionData, thisElementNeedsStyleRecalc); |
| 213 |
| 214 // Only match listData->siblings() against future siblings, not against
ourselves. |
| 215 for (const auto& invalidationSet : listData->siblings()) |
| 216 siblingData.pushInvalidationSet(*invalidationSet); |
| 217 } else { |
| 218 thisElementNeedsStyleRecalc = recursionData.matchesCurrentInvalidationSe
ts(element); |
| 219 thisElementNeedsStyleRecalc = siblingData.matchCurrentInvalidationSets(e
lement, recursionData, thisElementNeedsStyleRecalc); |
143 } | 220 } |
144 | 221 |
145 return recursionData.matchesCurrentInvalidationSets(element); | 222 return thisElementNeedsStyleRecalc; |
146 } | 223 } |
147 | 224 |
148 bool StyleInvalidator::invalidateChildren(Element& element, StyleInvalidator::Re
cursionData& recursionData) | 225 bool StyleInvalidator::invalidateChildren(Element& element, RecursionData& recur
sionData) |
149 { | 226 { |
| 227 SiblingData siblingData; |
| 228 |
150 bool someChildrenNeedStyleRecalc = false; | 229 bool someChildrenNeedStyleRecalc = false; |
151 for (ShadowRoot* root = element.youngestShadowRoot(); root; root = root->old
erShadowRoot()) { | 230 for (ShadowRoot* root = element.youngestShadowRoot(); root; root = root->old
erShadowRoot()) { |
152 if (!recursionData.treeBoundaryCrossing() && !root->childNeedsStyleInval
idation() && !root->needsStyleInvalidation()) | 231 if (!recursionData.treeBoundaryCrossing() && !root->childNeedsStyleInval
idation() && !root->needsStyleInvalidation()) |
153 continue; | 232 continue; |
154 for (Element* child = ElementTraversal::firstChild(*root); child; child
= ElementTraversal::nextSibling(*child)) { | 233 for (Element* child = ElementTraversal::firstChild(*root); child; child
= ElementTraversal::nextSibling(*child)) { |
155 bool childRecalced = invalidate(*child, recursionData); | 234 bool childRecalced = invalidate(*child, recursionData, siblingData); |
156 someChildrenNeedStyleRecalc = someChildrenNeedStyleRecalc || childRe
calced; | 235 someChildrenNeedStyleRecalc = someChildrenNeedStyleRecalc || childRe
calced; |
157 } | 236 } |
158 root->clearChildNeedsStyleInvalidation(); | 237 root->clearChildNeedsStyleInvalidation(); |
159 root->clearNeedsStyleInvalidation(); | 238 root->clearNeedsStyleInvalidation(); |
160 } | 239 } |
161 for (Element* child = ElementTraversal::firstChild(element); child; child =
ElementTraversal::nextSibling(*child)) { | 240 for (Element* child = ElementTraversal::firstChild(element); child; child =
ElementTraversal::nextSibling(*child)) { |
162 bool childRecalced = invalidate(*child, recursionData); | 241 bool childRecalced = invalidate(*child, recursionData, siblingData); |
163 someChildrenNeedStyleRecalc = someChildrenNeedStyleRecalc || childRecalc
ed; | 242 someChildrenNeedStyleRecalc = someChildrenNeedStyleRecalc || childRecalc
ed; |
164 } | 243 } |
165 return someChildrenNeedStyleRecalc; | 244 return someChildrenNeedStyleRecalc; |
166 } | 245 } |
167 | 246 |
168 bool StyleInvalidator::invalidate(Element& element, StyleInvalidator::RecursionD
ata& recursionData) | 247 bool StyleInvalidator::invalidate(Element& element, RecursionData& recursionData
, SiblingData& siblingData) |
169 { | 248 { |
170 RecursionCheckpoint checkpoint(&recursionData); | 249 RecursionCheckpoint checkpoint(&recursionData); |
| 250 siblingData.advance(); |
171 | 251 |
172 bool thisElementNeedsStyleRecalc = checkInvalidationSetsAgainstElement(eleme
nt, recursionData); | 252 bool thisElementNeedsStyleRecalc = checkInvalidationSetsAgainstElement(eleme
nt, recursionData, siblingData); |
173 | 253 |
174 bool someChildrenNeedStyleRecalc = false; | 254 bool someChildrenNeedStyleRecalc = false; |
175 if (recursionData.hasInvalidationSets() || element.childNeedsStyleInvalidati
on()) | 255 if (recursionData.hasInvalidationSets() || element.childNeedsStyleInvalidati
on()) |
176 someChildrenNeedStyleRecalc = invalidateChildren(element, recursionData)
; | 256 someChildrenNeedStyleRecalc = invalidateChildren(element, recursionData)
; |
177 | 257 |
178 if (thisElementNeedsStyleRecalc) { | 258 if (thisElementNeedsStyleRecalc) { |
179 ASSERT(!recursionData.wholeSubtreeInvalid()); | 259 ASSERT(!recursionData.wholeSubtreeInvalid()); |
180 element.setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracin
g::create(StyleChangeReason::StyleInvalidator)); | 260 element.setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracin
g::create(StyleChangeReason::StyleInvalidator)); |
181 } else if (recursionData.hasInvalidationSets() && someChildrenNeedStyleRecal
c) { | 261 } else if (recursionData.hasInvalidationSets() && someChildrenNeedStyleRecal
c) { |
182 // Clone the ComputedStyle in order to preserve correct style sharing, i
f possible. Otherwise recalc style. | 262 // Clone the ComputedStyle in order to preserve correct style sharing, i
f possible. Otherwise recalc style. |
(...skipping 15 matching lines...) Expand all Loading... |
198 } | 278 } |
199 | 279 |
200 DEFINE_TRACE(StyleInvalidator) | 280 DEFINE_TRACE(StyleInvalidator) |
201 { | 281 { |
202 #if ENABLE(OILPAN) | 282 #if ENABLE(OILPAN) |
203 visitor->trace(m_pendingInvalidationMap); | 283 visitor->trace(m_pendingInvalidationMap); |
204 #endif | 284 #endif |
205 } | 285 } |
206 | 286 |
207 } // namespace blink | 287 } // namespace blink |
OLD | NEW |