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 clearPendingInvalidations(); |
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 const InvalidationSetVector& descendant = invalidationLists.descendants(); |
49 element.setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTrac ing::create(StyleChangeReason::StyleInvalidator)); | 50 const InvalidationSetVector& sibling = invalidationLists.siblings(); |
50 clearInvalidation(element); | 51 |
51 return; | 52 bool requiresDescendantInvalidation = false; |
52 } | 53 |
53 if (invalidationSet->isEmpty()) { | 54 for (auto& invalidationSet : descendant) { |
54 element.setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracin g::create(StyleChangeReason::StyleInvalidator)); | 55 if (invalidationSet->wholeSubtreeInvalid()) { |
55 return; | 56 element.setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonFor Tracing::create(StyleChangeReason::StyleInvalidator)); |
57 return; | |
58 } | |
59 | |
60 ASSERT(invalidationSet->appliesDirectly() || !invalidationSet->isEmpty() ); | |
61 if (invalidationSet->appliesDirectly()) | |
62 element.setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTr acing::create(StyleChangeReason::StyleInvalidator)); | |
63 if (!invalidationSet->isEmpty()) | |
64 requiresDescendantInvalidation = true; | |
56 } | 65 } |
57 | 66 |
58 InvalidationList& list = ensurePendingInvalidationList(element); | 67 if (sibling.isEmpty() && !requiresDescendantInvalidation) |
59 list.append(invalidationSet); | 68 return; |
69 | |
60 element.setNeedsStyleInvalidation(); | 70 element.setNeedsStyleInvalidation(); |
61 } | 71 InvalidationLists& listData = ensurePendingInvalidationLists(element); |
62 | 72 |
63 StyleInvalidator::InvalidationList& StyleInvalidator::ensurePendingInvalidationL ist(Element& element) | 73 for (auto& invalidationSet : sibling) |
64 { | 74 listData.siblings().append(invalidationSet); |
65 PendingInvalidationMap::AddResult addResult = m_pendingInvalidationMap.add(& element, nullptr); | 75 |
66 if (addResult.isNewEntry) | 76 if (!requiresDescendantInvalidation) |
67 addResult.storedValue->value = adoptPtrWillBeNoop(new InvalidationList); | 77 return; |
68 return *addResult.storedValue->value; | 78 |
79 for (auto& invalidationSet : descendant) { | |
80 ASSERT(!invalidationSet->wholeSubtreeInvalid()); | |
81 if (!invalidationSet->isEmpty()) | |
82 listData.descendants().append(invalidationSet); | |
83 } | |
69 } | 84 } |
70 | 85 |
71 void StyleInvalidator::clearInvalidation(Element& element) | 86 void StyleInvalidator::clearInvalidation(Element& element) |
72 { | 87 { |
73 if (!element.needsStyleInvalidation()) | 88 if (!element.needsStyleInvalidation()) |
74 return; | 89 return; |
75 m_pendingInvalidationMap.remove(&element); | 90 m_pendingInvalidationMap.remove(&element); |
76 element.clearNeedsStyleInvalidation(); | 91 element.clearNeedsStyleInvalidation(); |
77 } | 92 } |
78 | 93 |
94 InvalidationLists& StyleInvalidator::ensurePendingInvalidationLists(Element& ele ment) | |
95 { | |
96 PendingInvalidationMap::AddResult addResult = m_pendingInvalidationMap.add(& element, nullptr); | |
97 if (addResult.isNewEntry) | |
98 addResult.storedValue->value = adoptPtr(new InvalidationLists); | |
99 return *addResult.storedValue->value; | |
100 } | |
101 | |
79 void StyleInvalidator::clearPendingInvalidations() | 102 void StyleInvalidator::clearPendingInvalidations() |
80 { | 103 { |
81 m_pendingInvalidationMap.clear(); | 104 m_pendingInvalidationMap.clear(); |
82 } | 105 } |
83 | 106 |
84 StyleInvalidator::StyleInvalidator() | 107 StyleInvalidator::StyleInvalidator() |
85 { | 108 { |
86 s_tracingEnabled = TRACE_EVENT_API_GET_CATEGORY_ENABLED(TRACE_DISABLED_BY_DE FAULT("devtools.timeline.invalidationTracking")); | 109 s_tracingEnabled = TRACE_EVENT_API_GET_CATEGORY_ENABLED(TRACE_DISABLED_BY_DE FAULT("devtools.timeline.invalidationTracking")); |
87 InvalidationSet::cacheTracingFlag(); | 110 InvalidationSet::cacheTracingFlag(); |
88 } | 111 } |
89 | 112 |
90 StyleInvalidator::~StyleInvalidator() | 113 StyleInvalidator::~StyleInvalidator() |
91 { | 114 { |
92 } | 115 } |
93 | 116 |
94 void StyleInvalidator::RecursionData::pushInvalidationSet(const InvalidationSet& invalidationSet) | 117 void StyleInvalidator::RecursionData::pushInvalidationSet(const InvalidationSet& invalidationSet) |
95 { | 118 { |
96 ASSERT(!m_wholeSubtreeInvalid); | 119 ASSERT(!m_wholeSubtreeInvalid); |
97 ASSERT(!invalidationSet.wholeSubtreeInvalid()); | 120 ASSERT(!invalidationSet.wholeSubtreeInvalid()); |
98 ASSERT(!invalidationSet.isEmpty()); | 121 ASSERT(!invalidationSet.isEmpty()); |
99 if (invalidationSet.treeBoundaryCrossing()) | 122 if (invalidationSet.treeBoundaryCrossing()) |
100 m_treeBoundaryCrossing = true; | 123 m_treeBoundaryCrossing = true; |
101 if (invalidationSet.insertionPointCrossing()) | 124 if (invalidationSet.insertionPointCrossing()) |
102 m_insertionPointCrossing = true; | 125 m_insertionPointCrossing = true; |
103 m_invalidationSets.append(&invalidationSet); | 126 m_invalidationSets.append(&invalidationSet); |
104 m_invalidateCustomPseudo = invalidationSet.customPseudoInvalid(); | 127 m_invalidateCustomPseudo = invalidationSet.customPseudoInvalid(); |
105 } | 128 } |
106 | 129 |
107 ALWAYS_INLINE bool StyleInvalidator::RecursionData::matchesCurrentInvalidationSe ts(Element& element) | 130 ALWAYS_INLINE bool StyleInvalidator::RecursionData::matchesCurrentInvalidationSe ts(Element& element) const |
108 { | 131 { |
109 if (m_invalidateCustomPseudo && element.shadowPseudoId() != nullAtom) { | 132 if (m_invalidateCustomPseudo && element.shadowPseudoId() != nullAtom) { |
110 TRACE_STYLE_INVALIDATOR_INVALIDATION_IF_ENABLED(element, InvalidateCusto mPseudo); | 133 TRACE_STYLE_INVALIDATOR_INVALIDATION_IF_ENABLED(element, InvalidateCusto mPseudo); |
111 return true; | 134 return true; |
112 } | 135 } |
113 | 136 |
114 if (m_insertionPointCrossing && element.isInsertionPoint()) | 137 if (m_insertionPointCrossing && element.isInsertionPoint()) |
115 return true; | 138 return true; |
116 | 139 |
117 for (const auto& invalidationSet : m_invalidationSets) { | 140 for (const auto& invalidationSet : m_invalidationSets) { |
118 if (invalidationSet->invalidatesElement(element)) | 141 if (invalidationSet->invalidatesElement(element)) |
119 return true; | 142 return true; |
120 } | 143 } |
121 | 144 |
122 return false; | 145 return false; |
123 } | 146 } |
124 | 147 |
125 ALWAYS_INLINE bool StyleInvalidator::checkInvalidationSetsAgainstElement(Element & element, StyleInvalidator::RecursionData& recursionData) | 148 void StyleInvalidator::SiblingData::pushInvalidationSet(const InvalidationSet& i nvalidationSet) |
149 { | |
150 unsigned invalidationLimit; | |
151 if (invalidationSet.maxDirectAdjacentSelectors() == std::numeric_limits<unsi gned>::max()) | |
152 invalidationLimit = std::numeric_limits<unsigned>::max(); | |
153 else | |
154 invalidationLimit = m_elementIndex + invalidationSet.maxDirectAdjacentSe lectors(); | |
155 m_invalidationEntries.append(Entry(&invalidationSet, invalidationLimit)); | |
156 } | |
157 | |
158 ALWAYS_INLINE bool StyleInvalidator::SiblingData::matchCurrentInvalidationSets(E lement& element, RecursionData& recursionData) | |
159 { | |
160 bool thisElementNeedsStyleRecalc = false; | |
161 ASSERT(!recursionData.wholeSubtreeInvalid()); | |
162 | |
163 unsigned index = 0; | |
164 while (index < m_invalidationEntries.size()) { | |
165 if (m_elementIndex > m_invalidationEntries[index].m_invalidationLimit) { | |
166 m_invalidationEntries[index] = m_invalidationEntries.last(); | |
167 m_invalidationEntries.removeLast(); | |
168 continue; | |
169 } | |
170 | |
171 const InvalidationSet* invalidationSet = m_invalidationEntries[index].m_ invalidationSet.get(); | |
172 | |
173 if (invalidationSet->invalidatesElement(element)) { | |
174 ASSERT(invalidationSet->appliesDirectly() || invalidationSet->descen dants()); | |
175 if (invalidationSet->appliesDirectly()) | |
176 thisElementNeedsStyleRecalc = true; | |
177 if (const InvalidationSet* descendants = invalidationSet->descendant s()) { | |
178 if (descendants->wholeSubtreeInvalid()) { | |
179 // Avoid directly setting SubtreeStyleChange on element, or ContainerNode::checkForChildrenAdjacentRuleChanges() | |
180 // may propagate the SubtreeStyleChange to our own siblings' subtrees. | |
rune
2015/09/14 23:06:51
I think that we ultimately want to end up with rem
Eric Willigers
2015/09/15 05:39:18
Yes, the complication is DOM changes, e.g. removin
| |
181 | |
182 for (Element* child = ElementTraversal::firstChild(element); child; child = ElementTraversal::nextSibling(*child)) { | |
183 child->setNeedsStyleRecalc(SubtreeStyleChange, StyleChan geReasonForTracing::create(StyleChangeReason::SiblingSelector)); | |
184 } | |
185 return true; | |
186 } | |
187 | |
188 recursionData.pushInvalidationSet(*descendants); | |
189 } | |
190 } | |
191 | |
192 ++index; | |
193 } | |
194 return thisElementNeedsStyleRecalc; | |
195 } | |
196 | |
197 ALWAYS_INLINE bool StyleInvalidator::checkInvalidationSetsAgainstElement(Element & element, RecursionData& recursionData, SiblingData& siblingData) | |
126 { | 198 { |
127 if (element.styleChangeType() >= SubtreeStyleChange || recursionData.wholeSu btreeInvalid()) { | 199 if (element.styleChangeType() >= SubtreeStyleChange || recursionData.wholeSu btreeInvalid()) { |
128 recursionData.setWholeSubtreeInvalid(); | 200 recursionData.setWholeSubtreeInvalid(); |
129 return false; | 201 return false; |
130 } | 202 } |
131 if (element.needsStyleInvalidation()) { | 203 |
132 if (InvalidationList* invalidationList = m_pendingInvalidationMap.get(&e lement)) { | 204 bool thisElementNeedsStyleRecalc = recursionData.matchesCurrentInvalidationS ets(element); |
133 for (const auto& invalidationSet : *invalidationList) | 205 thisElementNeedsStyleRecalc |= siblingData.matchCurrentInvalidationSets(elem ent, recursionData); |
206 | |
207 if (UNLIKELY(element.needsStyleInvalidation())) { | |
208 InvalidationLists* listData = m_pendingInvalidationMap.get(&element); | |
209 ASSERT(listData); | |
210 | |
211 if (!listData->descendants().isEmpty()) { | |
212 for (const auto& invalidationSet : listData->descendants()) | |
134 recursionData.pushInvalidationSet(*invalidationSet); | 213 recursionData.pushInvalidationSet(*invalidationSet); |
135 if (UNLIKELY(*s_tracingEnabled)) { | 214 if (UNLIKELY(*s_tracingEnabled)) { |
136 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timelin e.invalidationTracking"), | 215 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timelin e.invalidationTracking"), |
137 "StyleInvalidatorInvalidationTracking", | 216 "StyleInvalidatorInvalidationTracking", |
138 TRACE_EVENT_SCOPE_THREAD, | 217 TRACE_EVENT_SCOPE_THREAD, |
139 "data", InspectorStyleInvalidatorInvalidateEvent::invalidati onList(element, *invalidationList)); | 218 "data", InspectorStyleInvalidatorInvalidateEvent::invalidati onList(element, listData->descendants())); |
140 } | 219 } |
141 return true; | |
142 } | 220 } |
221 | |
222 for (const auto& invalidationSet : listData->siblings()) | |
223 siblingData.pushInvalidationSet(*invalidationSet); | |
143 } | 224 } |
144 | 225 |
145 return recursionData.matchesCurrentInvalidationSets(element); | 226 return thisElementNeedsStyleRecalc; |
146 } | 227 } |
147 | 228 |
148 bool StyleInvalidator::invalidateChildren(Element& element, StyleInvalidator::Re cursionData& recursionData) | 229 bool StyleInvalidator::invalidateChildren(Element& element, RecursionData& recur sionData) |
149 { | 230 { |
231 SiblingData siblingData; | |
232 | |
150 bool someChildrenNeedStyleRecalc = false; | 233 bool someChildrenNeedStyleRecalc = false; |
151 for (ShadowRoot* root = element.youngestShadowRoot(); root; root = root->old erShadowRoot()) { | 234 for (ShadowRoot* root = element.youngestShadowRoot(); root; root = root->old erShadowRoot()) { |
152 if (!recursionData.treeBoundaryCrossing() && !root->childNeedsStyleInval idation() && !root->needsStyleInvalidation()) | 235 if (!recursionData.treeBoundaryCrossing() && !root->childNeedsStyleInval idation() && !root->needsStyleInvalidation()) |
153 continue; | 236 continue; |
154 for (Element* child = ElementTraversal::firstChild(*root); child; child = ElementTraversal::nextSibling(*child)) { | 237 for (Element* child = ElementTraversal::firstChild(*root); child; child = ElementTraversal::nextSibling(*child)) { |
155 bool childRecalced = invalidate(*child, recursionData); | 238 bool childRecalced = invalidate(*child, recursionData, siblingData); |
156 someChildrenNeedStyleRecalc = someChildrenNeedStyleRecalc || childRe calced; | 239 someChildrenNeedStyleRecalc = someChildrenNeedStyleRecalc || childRe calced; |
157 } | 240 } |
158 root->clearChildNeedsStyleInvalidation(); | 241 root->clearChildNeedsStyleInvalidation(); |
159 root->clearNeedsStyleInvalidation(); | 242 root->clearNeedsStyleInvalidation(); |
160 } | 243 } |
161 for (Element* child = ElementTraversal::firstChild(element); child; child = ElementTraversal::nextSibling(*child)) { | 244 for (Element* child = ElementTraversal::firstChild(element); child; child = ElementTraversal::nextSibling(*child)) { |
162 bool childRecalced = invalidate(*child, recursionData); | 245 bool childRecalced = invalidate(*child, recursionData, siblingData); |
163 someChildrenNeedStyleRecalc = someChildrenNeedStyleRecalc || childRecalc ed; | 246 someChildrenNeedStyleRecalc = someChildrenNeedStyleRecalc || childRecalc ed; |
164 } | 247 } |
165 return someChildrenNeedStyleRecalc; | 248 return someChildrenNeedStyleRecalc; |
166 } | 249 } |
167 | 250 |
168 bool StyleInvalidator::invalidate(Element& element, StyleInvalidator::RecursionD ata& recursionData) | 251 bool StyleInvalidator::invalidate(Element& element, RecursionData& recursionData , SiblingData& siblingData) |
169 { | 252 { |
170 RecursionCheckpoint checkpoint(&recursionData); | 253 RecursionCheckpoint checkpoint(&recursionData); |
254 siblingData.advance(); | |
171 | 255 |
172 bool thisElementNeedsStyleRecalc = checkInvalidationSetsAgainstElement(eleme nt, recursionData); | 256 bool thisElementNeedsStyleRecalc = checkInvalidationSetsAgainstElement(eleme nt, recursionData, siblingData); |
173 | 257 |
174 bool someChildrenNeedStyleRecalc = false; | 258 bool someChildrenNeedStyleRecalc = false; |
175 if (recursionData.hasInvalidationSets() || element.childNeedsStyleInvalidati on()) | 259 if (recursionData.hasInvalidationSets() || element.childNeedsStyleInvalidati on()) |
176 someChildrenNeedStyleRecalc = invalidateChildren(element, recursionData) ; | 260 someChildrenNeedStyleRecalc = invalidateChildren(element, recursionData) ; |
177 | 261 |
178 if (thisElementNeedsStyleRecalc) { | 262 if (thisElementNeedsStyleRecalc) { |
179 ASSERT(!recursionData.wholeSubtreeInvalid()); | 263 ASSERT(!recursionData.wholeSubtreeInvalid()); |
180 element.setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracin g::create(StyleChangeReason::StyleInvalidator)); | 264 element.setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracin g::create(StyleChangeReason::StyleInvalidator)); |
181 } else if (recursionData.hasInvalidationSets() && someChildrenNeedStyleRecal c) { | 265 } else if (recursionData.hasInvalidationSets() && someChildrenNeedStyleRecal c) { |
182 // Clone the ComputedStyle in order to preserve correct style sharing, i f possible. Otherwise recalc style. | 266 // Clone the ComputedStyle in order to preserve correct style sharing, i f possible. Otherwise recalc style. |
(...skipping 15 matching lines...) Expand all Loading... | |
198 } | 282 } |
199 | 283 |
200 DEFINE_TRACE(StyleInvalidator) | 284 DEFINE_TRACE(StyleInvalidator) |
201 { | 285 { |
202 #if ENABLE(OILPAN) | 286 #if ENABLE(OILPAN) |
203 visitor->trace(m_pendingInvalidationMap); | 287 visitor->trace(m_pendingInvalidationMap); |
204 #endif | 288 #endif |
205 } | 289 } |
206 | 290 |
207 } // namespace blink | 291 } // namespace blink |
OLD | NEW |