OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) | 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) |
3 * (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com) | 3 * (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com) |
4 * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com) | 4 * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com) |
5 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All r ights reserved. | 5 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All r ights reserved. |
6 * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org> | 6 * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org> |
7 * Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org> | 7 * Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org> |
8 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.t orchmobile.com/) | 8 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.t orchmobile.com/) |
9 * Copyright (c) 2011, Code Aurora Forum. All rights reserved. | 9 * Copyright (c) 2011, Code Aurora Forum. All rights reserved. |
10 * Copyright (C) Research In Motion Limited 2011. All rights reserved. | 10 * Copyright (C) Research In Motion Limited 2011. All rights reserved. |
(...skipping 19 matching lines...) Expand all Loading... | |
30 #include "core/css/RuleFeature.h" | 30 #include "core/css/RuleFeature.h" |
31 | 31 |
32 #include "core/HTMLNames.h" | 32 #include "core/HTMLNames.h" |
33 #include "core/css/CSSSelector.h" | 33 #include "core/css/CSSSelector.h" |
34 #include "core/css/CSSSelectorList.h" | 34 #include "core/css/CSSSelectorList.h" |
35 #include "core/css/RuleSet.h" | 35 #include "core/css/RuleSet.h" |
36 #include "core/css/StyleRule.h" | 36 #include "core/css/StyleRule.h" |
37 #include "core/css/invalidation/DescendantInvalidationSet.h" | 37 #include "core/css/invalidation/DescendantInvalidationSet.h" |
38 #include "core/dom/Element.h" | 38 #include "core/dom/Element.h" |
39 #include "core/dom/Node.h" | 39 #include "core/dom/Node.h" |
40 #include "platform/RuntimeEnabledFeatures.h" | |
41 #include "wtf/BitVector.h" | 40 #include "wtf/BitVector.h" |
42 | 41 |
43 namespace blink { | 42 namespace blink { |
44 | 43 |
45 static bool isSkippableComponentForInvalidation(const CSSSelector& selector) | 44 static void assertSupportedMatch(CSSSelector::Match match) |
46 { | 45 { |
47 if (selector.match() == CSSSelector::Tag) { | 46 switch (match) { |
48 ASSERT(selector.tagQName().localName() == starAtom); | 47 case CSSSelector::Tag: |
49 return true; | 48 case CSSSelector::Id: |
49 case CSSSelector::Class: | |
50 case CSSSelector::AttributeExact: | |
51 case CSSSelector::AttributeSet: | |
52 case CSSSelector::AttributeHyphen: | |
53 case CSSSelector::AttributeList: | |
54 case CSSSelector::AttributeContain: | |
55 case CSSSelector::AttributeBegin: | |
56 case CSSSelector::AttributeEnd: | |
57 break; | |
58 case CSSSelector::Unknown: | |
59 case CSSSelector::PagePseudoClass: | |
60 // These should not appear in StyleRule selectors. | |
61 ASSERT_NOT_REACHED(); | |
62 break; | |
63 default: | |
64 // New match type added. Figure out if it needs a subtree recalc or not. | |
65 ASSERT_NOT_REACHED(); | |
66 break; | |
50 } | 67 } |
51 if (selector.match() == CSSSelector::PseudoElement) { | 68 } |
52 switch (selector.pseudoType()) { | 69 |
53 case CSSSelector::PseudoBefore: | 70 static void assertSupportedPseudo(CSSSelector::PseudoType type) |
54 case CSSSelector::PseudoAfter: | 71 { |
55 case CSSSelector::PseudoBackdrop: | 72 switch (type) { |
56 case CSSSelector::PseudoShadow: | |
57 return true; | |
58 default: | |
59 ASSERT(!selector.isCustomPseudoElement()); | |
60 return false; | |
61 } | |
62 } | |
63 if (selector.match() != CSSSelector::PseudoClass) | |
64 return false; | |
65 switch (selector.pseudoType()) { | |
66 case CSSSelector::PseudoEmpty: | 73 case CSSSelector::PseudoEmpty: |
67 case CSSSelector::PseudoFirstChild: | 74 case CSSSelector::PseudoFirstChild: |
68 case CSSSelector::PseudoFirstOfType: | 75 case CSSSelector::PseudoFirstOfType: |
69 case CSSSelector::PseudoLastChild: | 76 case CSSSelector::PseudoLastChild: |
70 case CSSSelector::PseudoLastOfType: | 77 case CSSSelector::PseudoLastOfType: |
71 case CSSSelector::PseudoOnlyChild: | 78 case CSSSelector::PseudoOnlyChild: |
72 case CSSSelector::PseudoOnlyOfType: | 79 case CSSSelector::PseudoOnlyOfType: |
73 case CSSSelector::PseudoNthChild: | 80 case CSSSelector::PseudoNthChild: |
74 case CSSSelector::PseudoNthOfType: | 81 case CSSSelector::PseudoNthOfType: |
75 case CSSSelector::PseudoNthLastChild: | 82 case CSSSelector::PseudoNthLastChild: |
76 case CSSSelector::PseudoNthLastOfType: | 83 case CSSSelector::PseudoNthLastOfType: |
77 case CSSSelector::PseudoLink: | 84 case CSSSelector::PseudoLink: |
78 case CSSSelector::PseudoVisited: | 85 case CSSSelector::PseudoVisited: |
86 case CSSSelector::PseudoAny: | |
79 case CSSSelector::PseudoAnyLink: | 87 case CSSSelector::PseudoAnyLink: |
80 case CSSSelector::PseudoHover: | 88 case CSSSelector::PseudoHover: |
81 case CSSSelector::PseudoDrag: | 89 case CSSSelector::PseudoDrag: |
82 case CSSSelector::PseudoFocus: | 90 case CSSSelector::PseudoFocus: |
83 case CSSSelector::PseudoActive: | 91 case CSSSelector::PseudoActive: |
84 case CSSSelector::PseudoChecked: | 92 case CSSSelector::PseudoChecked: |
85 case CSSSelector::PseudoEnabled: | 93 case CSSSelector::PseudoEnabled: |
86 case CSSSelector::PseudoDefault: | 94 case CSSSelector::PseudoDefault: |
87 case CSSSelector::PseudoDisabled: | 95 case CSSSelector::PseudoDisabled: |
88 case CSSSelector::PseudoOptional: | 96 case CSSSelector::PseudoOptional: |
89 case CSSSelector::PseudoRequired: | 97 case CSSSelector::PseudoRequired: |
90 case CSSSelector::PseudoReadOnly: | 98 case CSSSelector::PseudoReadOnly: |
91 case CSSSelector::PseudoReadWrite: | 99 case CSSSelector::PseudoReadWrite: |
92 case CSSSelector::PseudoValid: | 100 case CSSSelector::PseudoValid: |
93 case CSSSelector::PseudoInvalid: | 101 case CSSSelector::PseudoInvalid: |
94 case CSSSelector::PseudoIndeterminate: | 102 case CSSSelector::PseudoIndeterminate: |
95 case CSSSelector::PseudoTarget: | 103 case CSSSelector::PseudoTarget: |
104 case CSSSelector::PseudoBefore: | |
105 case CSSSelector::PseudoAfter: | |
106 case CSSSelector::PseudoBackdrop: | |
96 case CSSSelector::PseudoLang: | 107 case CSSSelector::PseudoLang: |
108 case CSSSelector::PseudoNot: | |
97 case CSSSelector::PseudoRoot: | 109 case CSSSelector::PseudoRoot: |
98 case CSSSelector::PseudoScope: | 110 case CSSSelector::PseudoScope: |
99 case CSSSelector::PseudoInRange: | 111 case CSSSelector::PseudoInRange: |
100 case CSSSelector::PseudoOutOfRange: | 112 case CSSSelector::PseudoOutOfRange: |
113 case CSSSelector::PseudoUserAgentCustomElement: | |
114 case CSSSelector::PseudoWebKitCustomElement: | |
101 case CSSSelector::PseudoUnresolved: | 115 case CSSSelector::PseudoUnresolved: |
116 case CSSSelector::PseudoHost: | |
117 case CSSSelector::PseudoShadow: | |
102 case CSSSelector::PseudoListBox: | 118 case CSSSelector::PseudoListBox: |
119 case CSSSelector::PseudoAutofill: | |
120 case CSSSelector::PseudoFullPageMedia: | |
121 case CSSSelector::PseudoResizer: | |
122 case CSSSelector::PseudoScrollbar: | |
123 case CSSSelector::PseudoScrollbarBack: | |
124 case CSSSelector::PseudoScrollbarButton: | |
125 case CSSSelector::PseudoScrollbarCorner: | |
126 case CSSSelector::PseudoScrollbarForward: | |
127 case CSSSelector::PseudoScrollbarThumb: | |
128 case CSSSelector::PseudoScrollbarTrack: | |
129 case CSSSelector::PseudoScrollbarTrackPiece: | |
130 case CSSSelector::PseudoWindowInactive: | |
131 case CSSSelector::PseudoCornerPresent: | |
132 case CSSSelector::PseudoDecrement: | |
133 case CSSSelector::PseudoIncrement: | |
134 case CSSSelector::PseudoHorizontal: | |
135 case CSSSelector::PseudoVertical: | |
136 case CSSSelector::PseudoStart: | |
137 case CSSSelector::PseudoEnd: | |
138 case CSSSelector::PseudoDoubleButton: | |
139 case CSSSelector::PseudoSingleButton: | |
140 case CSSSelector::PseudoNoButton: | |
141 case CSSSelector::PseudoSelection: | |
142 case CSSSelector::PseudoFullScreen: | |
143 case CSSSelector::PseudoFullScreenDocument: | |
144 case CSSSelector::PseudoFullScreenAncestor: | |
145 case CSSSelector::PseudoCue: | |
146 case CSSSelector::PseudoFutureCue: | |
147 case CSSSelector::PseudoPastCue: | |
148 case CSSSelector::PseudoContent: | |
149 case CSSSelector::PseudoSpatialNavigationFocus: | |
150 break; | |
151 case CSSSelector::PseudoNotParsed: | |
152 case CSSSelector::PseudoUnknown: | |
153 case CSSSelector::PseudoLeftPage: | |
154 case CSSSelector::PseudoRightPage: | |
155 case CSSSelector::PseudoFirstPage: | |
156 // These should not appear in StyleRule selectors. | |
157 ASSERT_NOT_REACHED(); | |
158 break; | |
159 default: | |
160 // New pseudo type added. Figure out if it needs a subtree recalc or not . | |
161 ASSERT_NOT_REACHED(); | |
162 break; | |
163 } | |
164 } | |
165 | |
166 static bool requiresSubtreeRecalc(const CSSSelector& selector) | |
167 { | |
168 if (!selector.matchesPseudoElement() && selector.match() != CSSSelector::Pse udoClass) { | |
169 assertSupportedMatch(selector.match()); | |
170 return false; | |
171 } | |
172 | |
173 switch (selector.pseudoType()) { | |
174 case CSSSelector::PseudoFirstLine: | |
175 // :first-line pseudo can apply to elements arbitrarily deep down in the | |
176 // DOM from its container given an arbitrary number of block descendants | |
177 // with no inline flow content in between. | |
178 case CSSSelector::PseudoFirstLetter: | |
179 // :first-letter pseudo elements can be arbitrarily deep down in the | |
180 // DOM from its container given an arbitrary number of block descendants | |
181 // with no text content in between. | |
182 case CSSSelector::PseudoHostContext: | |
183 // :host-context matches a shadow host, yet the simple selectors inside | |
184 // :host-context matches an ancestor of the shadow host. | |
103 return true; | 185 return true; |
104 default: | 186 default: |
187 assertSupportedPseudo(selector.pseudoType()); | |
105 return false; | 188 return false; |
106 } | 189 } |
107 } | 190 } |
108 | 191 |
109 RuleFeature::RuleFeature(StyleRule* rule, unsigned selectorIndex, bool hasDocume ntSecurityOrigin) | 192 RuleFeature::RuleFeature(StyleRule* rule, unsigned selectorIndex, bool hasDocume ntSecurityOrigin) |
110 : rule(rule) | 193 : rule(rule) |
111 , selectorIndex(selectorIndex) | 194 , selectorIndex(selectorIndex) |
112 , hasDocumentSecurityOrigin(hasDocumentSecurityOrigin) | 195 , hasDocumentSecurityOrigin(hasDocumentSecurityOrigin) |
113 { | 196 { |
114 } | 197 } |
115 | 198 |
116 void RuleFeature::trace(Visitor* visitor) | 199 void RuleFeature::trace(Visitor* visitor) |
117 { | 200 { |
118 visitor->trace(rule); | 201 visitor->trace(rule); |
119 } | 202 } |
120 | 203 |
121 // This method is somewhat conservative in what it accepts. | |
122 RuleFeatureSet::InvalidationSetMode RuleFeatureSet::invalidationSetModeForSelect or(const CSSSelector& selector) | |
123 { | |
124 bool foundCombinator = false; | |
125 bool foundIdent = false; | |
126 for (const CSSSelector* component = &selector; component; component = compon ent->tagHistory()) { | |
127 | |
128 if (component->match() == CSSSelector::Class || component->match() == CS SSelector::Id | |
129 || (component->match() == CSSSelector::Tag && component->tagQName(). localName() != starAtom) | |
130 || component->isAttributeSelector() || component->isCustomPseudoElem ent()) { | |
131 if (!foundCombinator) { | |
132 // We have found an invalidation set feature in the rightmost co mpound selector. | |
133 foundIdent = true; | |
134 } | |
135 } else if (component->pseudoType() == CSSSelector::PseudoNot | |
136 || component->pseudoType() == CSSSelector::PseudoHost | |
137 || component->pseudoType() == CSSSelector::PseudoAny) { | |
138 if (const CSSSelectorList* selectorList = component->selectorList()) { | |
139 // Features inside :not() are not added to the feature set, so c onsider it a universal selector. | |
140 bool foundUniversal = component->pseudoType() == CSSSelector::Ps eudoNot; | |
141 for (const CSSSelector* selector = selectorList->first(); select or; selector = CSSSelectorList::next(*selector)) { | |
142 // Find the invalidation set mode for each of the selectors in the selector list | |
143 // of a :not(), :host(), etc. For instance, ".x :-webkit-any (.a, .b)" yields an | |
144 // AddFeatures mode for both ".a" and ".b". ":-webkit-any(.a , *)" yields AddFeatures | |
145 // for ".a", but UseSubtreeStyleChange for "*". One sub-sele ctor without invalidation | |
146 // set features is sufficient to cause the selector to be a universal selector as far | |
147 // the invalidation set is concerned. | |
148 InvalidationSetMode subSelectorMode = invalidationSetModeFor Selector(*selector); | |
149 | |
150 // The sub-selector contained something unskippable, fall ba ck to whole subtree | |
151 // recalcs in collectFeaturesFromSelector. subSelectorMode w ill return | |
152 // UseSubtreeStyleChange since there are no combinators insi de the selector list, | |
153 // so translate it to UseLocalStyleChange if a combinator ha s been seen in the | |
154 // outer context. | |
155 // | |
156 // FIXME: Is UseSubtreeStyleChange ever needed as input to c ollectFeaturesFromSelector? | |
157 // That is, are there any selectors for which we need to use SubtreeStyleChange for | |
158 // changing features when present in the rightmost compound selector? | |
159 if (subSelectorMode == UseSubtreeStyleChange) | |
160 return foundCombinator ? UseLocalStyleChange : UseSubtre eStyleChange; | |
161 | |
162 // We found no features in the sub-selector, only skippable ones (foundIdent was | |
163 // false at the end of this method). That is a universal sel ector as far as the | |
164 // invalidation set is concerned. | |
165 if (subSelectorMode == UseLocalStyleChange) | |
166 foundUniversal = true; | |
167 } | |
168 if (!foundUniversal && !foundCombinator) { | |
169 // All sub-selectors contained invalidation set features and | |
170 // we are in the rightmost compound selector. | |
171 foundIdent = true; | |
172 } | |
173 } | |
174 } else if (!isSkippableComponentForInvalidation(*component)) { | |
175 return foundCombinator ? UseLocalStyleChange : UseSubtreeStyleChange ; | |
176 } | |
177 if (component->relation() != CSSSelector::SubSelector) | |
178 foundCombinator = true; | |
179 } | |
180 return foundIdent ? AddFeatures : UseLocalStyleChange; | |
181 } | |
182 | |
183 void RuleFeatureSet::extractInvalidationSetFeature(const CSSSelector& selector, InvalidationSetFeatures& features) | 204 void RuleFeatureSet::extractInvalidationSetFeature(const CSSSelector& selector, InvalidationSetFeatures& features) |
184 { | 205 { |
185 if (selector.match() == CSSSelector::Tag) | 206 if (selector.match() == CSSSelector::Tag && selector.tagQName().localName() != starAtom) |
186 features.tagName = selector.tagQName().localName(); | 207 features.setTagName(selector.tagQName().localName()); |
187 else if (selector.match() == CSSSelector::Id) | 208 else if (selector.match() == CSSSelector::Id) |
188 features.id = selector.value(); | 209 features.setId(selector.value()); |
189 else if (selector.match() == CSSSelector::Class) | 210 else if (selector.match() == CSSSelector::Class) |
190 features.classes.append(selector.value()); | 211 features.addClass(selector.value()); |
191 else if (selector.isAttributeSelector()) | 212 else if (selector.isAttributeSelector()) |
192 features.attributes.append(selector.attribute().localName()); | 213 features.addAttribute(selector.attribute().localName()); |
193 else if (selector.isCustomPseudoElement()) | 214 else if (selector.isCustomPseudoElement()) |
194 features.customPseudoElement = true; | 215 features.setHasCustomPseudo(); |
195 } | 216 } |
196 | 217 |
197 RuleFeatureSet::RuleFeatureSet() | 218 RuleFeatureSet::RuleFeatureSet() |
198 { | 219 { |
199 } | 220 } |
200 | 221 |
201 RuleFeatureSet::~RuleFeatureSet() | 222 RuleFeatureSet::~RuleFeatureSet() |
202 { | 223 { |
203 } | 224 } |
204 | 225 |
(...skipping 21 matching lines...) Expand all Loading... | |
226 return &ensurePseudoInvalidationSet(selector.pseudoType()); | 247 return &ensurePseudoInvalidationSet(selector.pseudoType()); |
227 default: | 248 default: |
228 break; | 249 break; |
229 } | 250 } |
230 } | 251 } |
231 return 0; | 252 return 0; |
232 } | 253 } |
233 | 254 |
234 // Given a selector, update the descendant invalidation sets for the features fo und | 255 // Given a selector, update the descendant invalidation sets for the features fo und |
235 // in the selector. The first step is to extract the features from the rightmost | 256 // in the selector. The first step is to extract the features from the rightmost |
236 // compound selector (extractInvalidationSetFeatures). Secondly, those features will be | 257 // compound selector (extractInvalidationSetFeatures). Secondly, add those featu res |
237 // added to the invalidation sets for the features found in the other compound s electors | 258 // to the invalidation sets for the features found in the other compound selecto rs |
238 // (addFeaturesToInvalidationSets). | 259 // (addFeaturesToInvalidationSets). If we find a feature in the right-most compo und |
260 // selector that requires a subtree recalc, we addFeaturesToInvalidationSets for the | |
261 // rightmost compound selector as well. | |
239 | 262 |
240 RuleFeatureSet::InvalidationSetMode RuleFeatureSet::updateInvalidationSets(const CSSSelector& selector) | 263 void RuleFeatureSet::updateInvalidationSets(const CSSSelector& selector) |
241 { | 264 { |
242 InvalidationSetMode mode = invalidationSetModeForSelector(selector); | |
243 if (mode != AddFeatures) | |
244 return mode; | |
245 | |
246 InvalidationSetFeatures features; | 265 InvalidationSetFeatures features; |
247 if (const CSSSelector* current = extractInvalidationSetFeatures(selector, fe atures, false)) | 266 if (const CSSSelector* current = extractInvalidationSetFeatures(selector, fe atures, false)) |
248 addFeaturesToInvalidationSets(*current, features); | 267 addFeaturesToInvalidationSets(*current, features); |
249 return AddFeatures; | |
250 } | 268 } |
251 | 269 |
252 const CSSSelector* RuleFeatureSet::extractInvalidationSetFeatures(const CSSSelec tor& selector, InvalidationSetFeatures& features, bool negated) | 270 const CSSSelector* RuleFeatureSet::extractInvalidationSetFeatures(const CSSSelec tor& selector, InvalidationSetFeatures& features, bool negated) |
253 { | 271 { |
254 for (const CSSSelector* current = &selector; current; current = current->tag History()) { | 272 for (const CSSSelector* current = &selector; current; current = current->tag History()) { |
255 if (!negated) | 273 if (!negated) |
256 extractInvalidationSetFeature(*current, features); | 274 extractInvalidationSetFeature(*current, features); |
257 // Initialize the entry in the invalidation set map, if supported. | 275 if (!invalidationSetForSelector(*current)) { |
258 invalidationSetForSelector(*current); | 276 if (requiresSubtreeRecalc(*current)) { |
259 if (current->pseudoType() == CSSSelector::PseudoHost || current->pseudoT ype() == CSSSelector::PseudoAny || current->pseudoType() == CSSSelector::PseudoN ot) { | 277 // Fall back to use subtree invalidations, even for features in the |
278 // rightmost compound selector. Returning the start &selector he re | |
279 // will make addFeaturesToInvalidationSets start marking invalid ation | |
280 // sets for subtree recalc for features in the rightmost compoun d | |
281 // selector. | |
282 features.hasFeatures = false; | |
chrishtr
2014/10/10 16:45:06
It's a weird to trigger subtree by setting hasFeat
| |
283 return &selector; | |
284 } | |
260 if (const CSSSelectorList* selectorList = current->selectorList()) { | 285 if (const CSSSelectorList* selectorList = current->selectorList()) { |
261 for (const CSSSelector* selector = selectorList->first(); select or; selector = CSSSelectorList::next(*selector)) | 286 const CSSSelector* subSelector = selectorList->first(); |
262 extractInvalidationSetFeatures(*selector, features, current- >pseudoType() == CSSSelector::PseudoNot); | 287 bool hadFeatures = features.hasFeatures; |
288 bool allSubSelectorsHaveFeatures = !!subSelector; | |
289 for (; subSelector; subSelector = CSSSelectorList::next(*subSele ctor)) { | |
290 features.hasFeatures = false; | |
291 if (extractInvalidationSetFeatures(*subSelector, features, c urrent->pseudoType() == CSSSelector::PseudoNot)) { | |
292 // A non-null return means the sub-selector contained a selector | |
293 // which requiresSubtreeRecalc(). Return the rightmost s elector | |
294 // to mark for subtree recalcs like above. | |
295 ASSERT(!features.hasFeatures); | |
296 return &selector; | |
297 } | |
298 allSubSelectorsHaveFeatures &= features.hasFeatures; | |
299 } | |
300 features.hasFeatures = hadFeatures || allSubSelectorsHaveFeature s; | |
263 } | 301 } |
264 } | 302 } |
265 | 303 |
266 switch (current->relation()) { | 304 if (current->relation() == CSSSelector::SubSelector) |
267 case CSSSelector::SubSelector: | 305 continue; |
268 break; | 306 |
269 case CSSSelector::ShadowPseudo: | 307 if (current->isShadowSelector()) |
270 case CSSSelector::ShadowDeep: | |
271 features.treeBoundaryCrossing = true; | 308 features.treeBoundaryCrossing = true; |
272 return current->tagHistory(); | 309 |
273 case CSSSelector::DirectAdjacent: | 310 features.adjacent = current->isAdjacentSelector(); |
274 case CSSSelector::IndirectAdjacent: | 311 |
275 features.wholeSubtree = true; | 312 return current->tagHistory(); |
276 return current->tagHistory(); | |
277 case CSSSelector::Descendant: | |
278 case CSSSelector::Child: | |
279 return current->tagHistory(); | |
280 } | |
281 } | 313 } |
282 return 0; | 314 return 0; |
283 } | 315 } |
284 | 316 |
285 // Add features extracted from the rightmost compound selector to descendant inv alidation | 317 // Add features extracted from the rightmost compound selector to descendant inv alidation |
286 // sets for features found in other compound selectors. | 318 // sets for features found in other compound selectors. |
287 // | 319 // |
288 // Style invalidation is currently supported for descendants only, not for sibli ng subtrees. | 320 // Style invalidation is currently supported for descendants only, not for sibli ng subtrees. |
289 // We use wholeSubtree invalidation for features found left of adjacent combinat ors as | 321 // We use wholeSubtree invalidation for features found left of adjacent combinat ors as |
290 // SubtreeStyleChange will force sibling subtree recalc in | 322 // SubtreeStyleChange will force sibling subtree recalc in |
291 // ContainerNode::checkForChildrenAdjacentRuleChanges. | 323 // ContainerNode::checkForChildrenAdjacentRuleChanges. |
292 // | 324 // |
293 // As we encounter a descendant type of combinator, the features only need to be checked | 325 // As we encounter a descendant type of combinator, the features only need to be checked |
294 // against descendants in the same subtree only. Hence wholeSubtree is reset to false. | 326 // against descendants in the same subtree only. Hence wholeSubtree is reset to false. |
295 | 327 |
328 void RuleFeatureSet::addFeaturesToInvalidationSet(DescendantInvalidationSet& inv alidationSet, const InvalidationSetFeatures& features) | |
329 { | |
330 if (features.treeBoundaryCrossing) | |
331 invalidationSet.setTreeBoundaryCrossing(); | |
332 if (features.insertionPointCrossing) | |
333 invalidationSet.setInsertionPointCrossing(); | |
334 if (features.useSubtreeInvalidation()) { | |
335 invalidationSet.setWholeSubtreeInvalid(); | |
336 return; | |
337 } | |
338 if (!features.id.isEmpty()) | |
339 invalidationSet.addId(features.id); | |
340 if (!features.tagName.isEmpty()) | |
341 invalidationSet.addTagName(features.tagName); | |
342 for (const auto& className : features.classes) | |
343 invalidationSet.addClass(className); | |
344 for (const auto& attribute : features.attributes) | |
345 invalidationSet.addAttribute(attribute); | |
346 if (features.customPseudoElement) | |
347 invalidationSet.setCustomPseudoInvalid(); | |
348 } | |
349 | |
296 void RuleFeatureSet::addFeaturesToInvalidationSets(const CSSSelector& selector, InvalidationSetFeatures& features) | 350 void RuleFeatureSet::addFeaturesToInvalidationSets(const CSSSelector& selector, InvalidationSetFeatures& features) |
297 { | 351 { |
298 for (const CSSSelector* current = &selector; current; current = current->tag History()) { | 352 for (const CSSSelector* current = &selector; current; current = current->tag History()) { |
299 if (DescendantInvalidationSet* invalidationSet = invalidationSetForSelec tor(*current)) { | 353 if (DescendantInvalidationSet* invalidationSet = invalidationSetForSelec tor(*current)) { |
300 if (features.treeBoundaryCrossing) | 354 addFeaturesToInvalidationSet(*invalidationSet, features); |
301 invalidationSet->setTreeBoundaryCrossing(); | |
302 if (features.wholeSubtree) { | |
303 invalidationSet->setWholeSubtreeInvalid(); | |
304 } else { | |
305 if (!features.id.isEmpty()) | |
306 invalidationSet->addId(features.id); | |
307 if (!features.tagName.isEmpty()) | |
308 invalidationSet->addTagName(features.tagName); | |
309 for (Vector<AtomicString>::const_iterator it = features.classes. begin(); it != features.classes.end(); ++it) | |
310 invalidationSet->addClass(*it); | |
311 for (Vector<AtomicString>::const_iterator it = features.attribut es.begin(); it != features.attributes.end(); ++it) | |
312 invalidationSet->addAttribute(*it); | |
313 if (features.customPseudoElement) | |
314 invalidationSet->setCustomPseudoInvalid(); | |
315 } | |
316 } else { | 355 } else { |
317 if (current->pseudoType() == CSSSelector::PseudoHost) | 356 if (current->isTreeBoundaryCrossing()) |
318 features.treeBoundaryCrossing = true; | 357 features.treeBoundaryCrossing = true; |
358 if (current->isInsertionPointCrossing()) | |
359 features.insertionPointCrossing = true; | |
319 if (const CSSSelectorList* selectorList = current->selectorList()) { | 360 if (const CSSSelectorList* selectorList = current->selectorList()) { |
320 ASSERT(current->pseudoType() == CSSSelector::PseudoHost || curre nt->pseudoType() == CSSSelector::PseudoAny || current->pseudoType() == CSSSelect or::PseudoNot); | |
321 for (const CSSSelector* selector = selectorList->first(); select or; selector = CSSSelectorList::next(*selector)) | 361 for (const CSSSelector* selector = selectorList->first(); select or; selector = CSSSelectorList::next(*selector)) |
322 addFeaturesToInvalidationSets(*selector, features); | 362 addFeaturesToInvalidationSets(*selector, features); |
323 } | 363 } |
324 } | 364 } |
325 switch (current->relation()) { | 365 |
326 case CSSSelector::SubSelector: | 366 if (current->relation() == CSSSelector::SubSelector) |
327 break; | 367 continue; |
328 case CSSSelector::ShadowPseudo: | 368 |
329 case CSSSelector::ShadowDeep: | 369 if (current->isShadowSelector()) |
330 features.treeBoundaryCrossing = true; | 370 features.treeBoundaryCrossing = true; |
331 features.wholeSubtree = false; | 371 |
332 break; | 372 features.adjacent = current->isAdjacentSelector(); |
333 case CSSSelector::Descendant: | |
334 case CSSSelector::Child: | |
335 features.wholeSubtree = false; | |
336 break; | |
337 case CSSSelector::DirectAdjacent: | |
338 case CSSSelector::IndirectAdjacent: | |
339 features.wholeSubtree = true; | |
340 break; | |
341 } | |
342 } | 373 } |
343 } | 374 } |
344 | 375 |
345 void RuleFeatureSet::addContentAttr(const AtomicString& attributeName) | 376 void RuleFeatureSet::addContentAttr(const AtomicString& attributeName) |
346 { | 377 { |
347 ensureAttributeInvalidationSet(attributeName); | 378 ensureAttributeInvalidationSet(attributeName); |
348 } | 379 } |
349 | 380 |
350 void RuleFeatureSet::collectFeaturesFromRuleData(const RuleData& ruleData) | 381 void RuleFeatureSet::collectFeaturesFromRuleData(const RuleData& ruleData) |
351 { | 382 { |
383 updateInvalidationSets(ruleData.selector()); | |
384 | |
352 FeatureMetadata metadata; | 385 FeatureMetadata metadata; |
353 InvalidationSetMode mode = updateInvalidationSets(ruleData.selector()); | 386 collectFeaturesFromSelector(ruleData.selector(), metadata); |
354 | |
355 collectFeaturesFromSelector(ruleData.selector(), metadata, mode); | |
356 m_metadata.add(metadata); | 387 m_metadata.add(metadata); |
357 | 388 |
358 if (metadata.foundSiblingSelector) | 389 if (metadata.foundSiblingSelector) |
359 siblingRules.append(RuleFeature(ruleData.rule(), ruleData.selectorIndex( ), ruleData.hasDocumentSecurityOrigin())); | 390 siblingRules.append(RuleFeature(ruleData.rule(), ruleData.selectorIndex( ), ruleData.hasDocumentSecurityOrigin())); |
360 if (ruleData.containsUncommonAttributeSelector()) | 391 if (ruleData.containsUncommonAttributeSelector()) |
361 uncommonAttributeRules.append(RuleFeature(ruleData.rule(), ruleData.sele ctorIndex(), ruleData.hasDocumentSecurityOrigin())); | 392 uncommonAttributeRules.append(RuleFeature(ruleData.rule(), ruleData.sele ctorIndex(), ruleData.hasDocumentSecurityOrigin())); |
362 } | 393 } |
363 | 394 |
364 DescendantInvalidationSet& RuleFeatureSet::ensureClassInvalidationSet(const Atom icString& className) | 395 DescendantInvalidationSet& RuleFeatureSet::ensureClassInvalidationSet(const Atom icString& className) |
365 { | 396 { |
(...skipping 20 matching lines...) Expand all Loading... | |
386 } | 417 } |
387 | 418 |
388 DescendantInvalidationSet& RuleFeatureSet::ensurePseudoInvalidationSet(CSSSelect or::PseudoType pseudoType) | 419 DescendantInvalidationSet& RuleFeatureSet::ensurePseudoInvalidationSet(CSSSelect or::PseudoType pseudoType) |
389 { | 420 { |
390 PseudoTypeInvalidationSetMap::AddResult addResult = m_pseudoInvalidationSets .add(pseudoType, nullptr); | 421 PseudoTypeInvalidationSetMap::AddResult addResult = m_pseudoInvalidationSets .add(pseudoType, nullptr); |
391 if (addResult.isNewEntry) | 422 if (addResult.isNewEntry) |
392 addResult.storedValue->value = DescendantInvalidationSet::create(); | 423 addResult.storedValue->value = DescendantInvalidationSet::create(); |
393 return *addResult.storedValue->value; | 424 return *addResult.storedValue->value; |
394 } | 425 } |
395 | 426 |
396 void RuleFeatureSet::collectFeaturesFromSelector(const CSSSelector& selector, Ru leFeatureSet::FeatureMetadata& metadata, InvalidationSetMode mode) | 427 void RuleFeatureSet::collectFeaturesFromSelector(const CSSSelector& selector, Ru leFeatureSet::FeatureMetadata& metadata) |
397 { | 428 { |
398 unsigned maxDirectAdjacentSelectors = 0; | 429 unsigned maxDirectAdjacentSelectors = 0; |
399 | 430 |
400 for (const CSSSelector* current = &selector; current; current = current->tag History()) { | 431 for (const CSSSelector* current = &selector; current; current = current->tag History()) { |
401 if (mode != AddFeatures) { | |
402 if (DescendantInvalidationSet* invalidationSet = invalidationSetForS elector(*current)) { | |
403 if (mode == UseSubtreeStyleChange) | |
404 invalidationSet->setWholeSubtreeInvalid(); | |
405 } | |
406 } | |
407 if (current->pseudoType() == CSSSelector::PseudoFirstLine) | 432 if (current->pseudoType() == CSSSelector::PseudoFirstLine) |
408 metadata.usesFirstLineRules = true; | 433 metadata.usesFirstLineRules = true; |
409 if (current->isDirectAdjacentSelector()) { | 434 if (current->isDirectAdjacentSelector()) { |
410 maxDirectAdjacentSelectors++; | 435 maxDirectAdjacentSelectors++; |
411 } else if (maxDirectAdjacentSelectors) { | 436 } else if (maxDirectAdjacentSelectors) { |
412 if (maxDirectAdjacentSelectors > metadata.maxDirectAdjacentSelectors ) | 437 if (maxDirectAdjacentSelectors > metadata.maxDirectAdjacentSelectors ) |
413 metadata.maxDirectAdjacentSelectors = maxDirectAdjacentSelectors ; | 438 metadata.maxDirectAdjacentSelectors = maxDirectAdjacentSelectors ; |
414 maxDirectAdjacentSelectors = 0; | 439 maxDirectAdjacentSelectors = 0; |
415 } | 440 } |
416 if (current->isSiblingSelector()) | 441 if (current->isSiblingSelector()) |
417 metadata.foundSiblingSelector = true; | 442 metadata.foundSiblingSelector = true; |
418 | 443 |
419 collectFeaturesFromSelectorList(current->selectorList(), metadata, mode) ; | 444 const CSSSelectorList* selectorList = current->selectorList(); |
445 if (!selectorList) | |
446 continue; | |
420 | 447 |
421 if (mode == UseLocalStyleChange && current->relation() != CSSSelector::S ubSelector) | 448 for (const CSSSelector* selector = selectorList->first(); selector; sele ctor = CSSSelectorList::next(*selector)) |
422 mode = UseSubtreeStyleChange; | 449 collectFeaturesFromSelector(*selector, metadata); |
423 } | 450 } |
424 | 451 |
425 ASSERT(!maxDirectAdjacentSelectors); | 452 ASSERT(!maxDirectAdjacentSelectors); |
426 } | 453 } |
427 | 454 |
428 void RuleFeatureSet::collectFeaturesFromSelectorList(const CSSSelectorList* sele ctorList, RuleFeatureSet::FeatureMetadata& metadata, InvalidationSetMode mode) | |
429 { | |
430 if (!selectorList) | |
431 return; | |
432 | |
433 for (const CSSSelector* selector = selectorList->first(); selector; selector = CSSSelectorList::next(*selector)) | |
434 collectFeaturesFromSelector(*selector, metadata, mode); | |
435 } | |
436 | |
437 void RuleFeatureSet::FeatureMetadata::add(const FeatureMetadata& other) | 455 void RuleFeatureSet::FeatureMetadata::add(const FeatureMetadata& other) |
438 { | 456 { |
439 usesFirstLineRules = usesFirstLineRules || other.usesFirstLineRules; | 457 usesFirstLineRules = usesFirstLineRules || other.usesFirstLineRules; |
440 maxDirectAdjacentSelectors = std::max(maxDirectAdjacentSelectors, other.maxD irectAdjacentSelectors); | 458 maxDirectAdjacentSelectors = std::max(maxDirectAdjacentSelectors, other.maxD irectAdjacentSelectors); |
441 } | 459 } |
442 | 460 |
443 void RuleFeatureSet::FeatureMetadata::clear() | 461 void RuleFeatureSet::FeatureMetadata::clear() |
444 { | 462 { |
445 usesFirstLineRules = false; | 463 usesFirstLineRules = false; |
446 foundSiblingSelector = false; | 464 foundSiblingSelector = false; |
447 maxDirectAdjacentSelectors = 0; | 465 maxDirectAdjacentSelectors = 0; |
448 } | 466 } |
449 | 467 |
450 void RuleFeatureSet::add(const RuleFeatureSet& other) | 468 void RuleFeatureSet::add(const RuleFeatureSet& other) |
451 { | 469 { |
452 for (InvalidationSetMap::const_iterator it = other.m_classInvalidationSets.b egin(); it != other.m_classInvalidationSets.end(); ++it) | 470 for (const auto& it : other.m_classInvalidationSets) |
453 ensureClassInvalidationSet(it->key).combine(*it->value); | 471 ensureClassInvalidationSet(it.key).combine(*it.value); |
454 for (InvalidationSetMap::const_iterator it = other.m_attributeInvalidationSe ts.begin(); it != other.m_attributeInvalidationSets.end(); ++it) | 472 for (const auto& it : other.m_attributeInvalidationSets) |
455 ensureAttributeInvalidationSet(it->key).combine(*it->value); | 473 ensureAttributeInvalidationSet(it.key).combine(*it.value); |
456 for (InvalidationSetMap::const_iterator it = other.m_idInvalidationSets.begi n(); it != other.m_idInvalidationSets.end(); ++it) | 474 for (const auto& it : other.m_idInvalidationSets) |
457 ensureIdInvalidationSet(it->key).combine(*it->value); | 475 ensureIdInvalidationSet(it.key).combine(*it.value); |
458 for (PseudoTypeInvalidationSetMap::const_iterator it = other.m_pseudoInvalid ationSets.begin(); it != other.m_pseudoInvalidationSets.end(); ++it) | 476 for (const auto& it : other.m_pseudoInvalidationSets) |
459 ensurePseudoInvalidationSet(static_cast<CSSSelector::PseudoType>(it->key )).combine(*it->value); | 477 ensurePseudoInvalidationSet(static_cast<CSSSelector::PseudoType>(it.key) ).combine(*it.value); |
460 | 478 |
461 m_metadata.add(other.m_metadata); | 479 m_metadata.add(other.m_metadata); |
462 | 480 |
463 siblingRules.appendVector(other.siblingRules); | 481 siblingRules.appendVector(other.siblingRules); |
464 uncommonAttributeRules.appendVector(other.uncommonAttributeRules); | 482 uncommonAttributeRules.appendVector(other.uncommonAttributeRules); |
465 } | 483 } |
466 | 484 |
467 void RuleFeatureSet::clear() | 485 void RuleFeatureSet::clear() |
468 { | 486 { |
469 siblingRules.clear(); | 487 siblingRules.clear(); |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
564 visitor->trace(uncommonAttributeRules); | 582 visitor->trace(uncommonAttributeRules); |
565 visitor->trace(m_classInvalidationSets); | 583 visitor->trace(m_classInvalidationSets); |
566 visitor->trace(m_attributeInvalidationSets); | 584 visitor->trace(m_attributeInvalidationSets); |
567 visitor->trace(m_idInvalidationSets); | 585 visitor->trace(m_idInvalidationSets); |
568 visitor->trace(m_pseudoInvalidationSets); | 586 visitor->trace(m_pseudoInvalidationSets); |
569 visitor->trace(m_styleInvalidator); | 587 visitor->trace(m_styleInvalidator); |
570 #endif | 588 #endif |
571 } | 589 } |
572 | 590 |
573 } // namespace blink | 591 } // namespace blink |
OLD | NEW |