2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.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 rights reserved.
6 * Copyright (C) 2007 Alexey Proskuryakov <ap@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.torchmobile.com/)
9 * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
10 * Copyright (C) Research In Motion Limited 2011. All rights reserved.
11 * Copyright (C) 2012 Google Inc. All rights reserved.
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Library General Public
15 * License as published by the Free Software Foundation; either
16 * version 2 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Library General Public License for more details.
23 * You should have received a copy of the GNU Library General Public License
24 * along with this library; see the file COPYING.LIB. If not, write to
25 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
26 * Boston, MA 02110-1301, USA.
30 #include "core/css/RuleFeature.h"
32 #include "core/HTMLNames.h"
33 #include "core/css/CSSSelector.h"
34 #include "core/css/CSSSelectorList.h"
35 #include "core/css/RuleSet.h"
36 #include "core/css/StyleRule.h"
37 #include "core/css/invalidation/DescendantInvalidationSet.h"
38 #include "core/dom/Element.h"
39 #include "core/dom/Node.h"
40 #include "core/inspector/InspectorTraceEvents.h"
41 #include "wtf/BitVector.h"
47 static bool supportsInvalidation(CSSSelector::Match match)
50 case CSSSelector::Tag:
52 case CSSSelector::Class:
53 case CSSSelector::AttributeExact:
54 case CSSSelector::AttributeSet:
55 case CSSSelector::AttributeHyphen:
56 case CSSSelector::AttributeList:
57 case CSSSelector::AttributeContain:
58 case CSSSelector::AttributeBegin:
59 case CSSSelector::AttributeEnd:
61 case CSSSelector::Unknown:
62 case CSSSelector::PagePseudoClass:
63 // These should not appear in StyleRule selectors.
67 // New match type added. Figure out if it needs a subtree invalidation or not.
73 static bool supportsInvalidation(CSSSelector::PseudoType type)
76 case CSSSelector::PseudoEmpty:
77 case CSSSelector::PseudoFirstChild:
78 case CSSSelector::PseudoFirstOfType:
79 case CSSSelector::PseudoLastChild:
80 case CSSSelector::PseudoLastOfType:
81 case CSSSelector::PseudoOnlyChild:
82 case CSSSelector::PseudoOnlyOfType:
83 case CSSSelector::PseudoNthChild:
84 case CSSSelector::PseudoNthOfType:
85 case CSSSelector::PseudoNthLastChild:
86 case CSSSelector::PseudoNthLastOfType:
87 case CSSSelector::PseudoLink:
88 case CSSSelector::PseudoVisited:
89 case CSSSelector::PseudoAny:
90 case CSSSelector::PseudoAnyLink:
91 case CSSSelector::PseudoAutofill:
92 case CSSSelector::PseudoHover:
93 case CSSSelector::PseudoDrag:
94 case CSSSelector::PseudoFocus:
95 case CSSSelector::PseudoActive:
96 case CSSSelector::PseudoChecked:
97 case CSSSelector::PseudoEnabled:
98 case CSSSelector::PseudoFullPageMedia:
99 case CSSSelector::PseudoDefault:
100 case CSSSelector::PseudoDisabled:
101 case CSSSelector::PseudoOptional:
102 case CSSSelector::PseudoRequired:
103 case CSSSelector::PseudoReadOnly:
104 case CSSSelector::PseudoReadWrite:
105 case CSSSelector::PseudoValid:
106 case CSSSelector::PseudoInvalid:
107 case CSSSelector::PseudoIndeterminate:
108 case CSSSelector::PseudoTarget:
109 case CSSSelector::PseudoBefore:
110 case CSSSelector::PseudoAfter:
111 case CSSSelector::PseudoBackdrop:
112 case CSSSelector::PseudoLang:
113 case CSSSelector::PseudoNot:
114 case CSSSelector::PseudoResizer:
115 case CSSSelector::PseudoRoot:
116 case CSSSelector::PseudoScope:
117 case CSSSelector::PseudoScrollbar:
118 case CSSSelector::PseudoScrollbarButton:
119 case CSSSelector::PseudoScrollbarCorner:
120 case CSSSelector::PseudoScrollbarThumb:
121 case CSSSelector::PseudoScrollbarTrack:
122 case CSSSelector::PseudoScrollbarTrackPiece:
123 case CSSSelector::PseudoWindowInactive:
124 case CSSSelector::PseudoSelection:
125 case CSSSelector::PseudoCornerPresent:
126 case CSSSelector::PseudoDecrement:
127 case CSSSelector::PseudoIncrement:
128 case CSSSelector::PseudoHorizontal:
129 case CSSSelector::PseudoVertical:
130 case CSSSelector::PseudoStart:
131 case CSSSelector::PseudoEnd:
132 case CSSSelector::PseudoDoubleButton:
133 case CSSSelector::PseudoSingleButton:
134 case CSSSelector::PseudoNoButton:
135 case CSSSelector::PseudoFullScreen:
136 case CSSSelector::PseudoFullScreenDocument:
137 case CSSSelector::PseudoFullScreenAncestor:
138 case CSSSelector::PseudoInRange:
139 case CSSSelector::PseudoOutOfRange:
140 case CSSSelector::PseudoWebKitCustomElement:
141 case CSSSelector::PseudoUnresolved:
142 case CSSSelector::PseudoContent:
143 case CSSSelector::PseudoHost:
144 case CSSSelector::PseudoShadow:
145 case CSSSelector::PseudoListBox:
147 case CSSSelector::PseudoNotParsed:
148 case CSSSelector::PseudoUnknown:
149 case CSSSelector::PseudoLeftPage:
150 case CSSSelector::PseudoRightPage:
151 case CSSSelector::PseudoFirstPage:
152 // These should not appear in StyleRule selectors.
153 ASSERT_NOT_REACHED();
156 // New pseudo type added. Figure out if it needs a subtree invalidation or not.
157 ASSERT_NOT_REACHED();
162 #endif // ENABLE(ASSERT)
164 static bool requiresSubtreeInvalidation(const CSSSelector& selector)
166 if (!selector.matchesPseudoElement() && selector.match() != CSSSelector::PseudoClass) {
167 ASSERT(supportsInvalidation(selector.match()));
171 switch (selector.pseudoType()) {
172 case CSSSelector::PseudoFirstLine:
173 case CSSSelector::PseudoFirstLetter:
174 case CSSSelector::PseudoCue:
175 case CSSSelector::PseudoFutureCue:
176 case CSSSelector::PseudoPastCue:
177 case CSSSelector::PseudoSpatialNavigationFocus:
178 // FIXME: Most pseudo classes/elements above can be supported and moved
179 // to assertSupportedPseudo(). Move on a case-by-case basis. If they
180 // require subtree invalidation, document why.
181 case CSSSelector::PseudoHostContext:
182 // :host-context matches a shadow host, yet the simple selectors inside
183 // :host-context matches an ancestor of the shadow host.
186 ASSERT(supportsInvalidation(selector.pseudoType()));
191 RuleFeature::RuleFeature(StyleRule* rule, unsigned selectorIndex, bool hasDocumentSecurityOrigin)
193 , selectorIndex(selectorIndex)
194 , hasDocumentSecurityOrigin(hasDocumentSecurityOrigin)
198 void RuleFeature::trace(Visitor* visitor)
200 visitor->trace(rule);
203 // This method is somewhat conservative in what it accepts.
204 RuleFeatureSet::InvalidationSetMode RuleFeatureSet::invalidationSetModeForSelector(const CSSSelector& selector)
206 bool foundCombinator = false;
207 bool foundIdent = false;
208 for (const CSSSelector* component = &selector; component; component = component->tagHistory()) {
210 if (component->match() == CSSSelector::Class || component->match() == CSSSelector::Id
211 || (component->match() == CSSSelector::Tag && component->tagQName().localName() != starAtom)
212 || component->isAttributeSelector() || component->isCustomPseudoElement()) {
213 if (!foundCombinator) {
214 // We have found an invalidation set feature in the rightmost compound selector.
217 } else if (component->pseudoType() == CSSSelector::PseudoNot
218 || component->pseudoType() == CSSSelector::PseudoHost
219 || component->pseudoType() == CSSSelector::PseudoAny) {
220 if (const CSSSelectorList* selectorList = component->selectorList()) {
221 // Features inside :not() are not added to the feature set, so consider it a universal selector.
222 bool foundUniversal = component->pseudoType() == CSSSelector::PseudoNot;
223 for (const CSSSelector* selector = selectorList->first(); selector; selector = CSSSelectorList::next(*selector)) {
224 // Find the invalidation set mode for each of the selectors in the selector list
225 // of a :not(), :host(), etc. For instance, ".x :-webkit-any(.a, .b)" yields an
226 // AddFeatures mode for both ".a" and ".b". ":-webkit-any(.a, *)" yields AddFeatures
227 // for ".a", but UseSubtreeStyleChange for "*". One sub-selector without invalidation
228 // set features is sufficient to cause the selector to be a universal selector as far
229 // the invalidation set is concerned.
230 InvalidationSetMode subSelectorMode = invalidationSetModeForSelector(*selector);
232 // The sub-selector contained something unskippable, fall back to whole subtree
233 // recalcs in collectFeaturesFromSelector. subSelectorMode will return
234 // UseSubtreeStyleChange since there are no combinators inside the selector list,
235 // so translate it to UseLocalStyleChange if a combinator has been seen in the
238 // FIXME: Is UseSubtreeStyleChange ever needed as input to collectFeaturesFromSelector?
239 // That is, are there any selectors for which we need to use SubtreeStyleChange for
240 // changing features when present in the rightmost compound selector?
241 if (subSelectorMode == UseSubtreeStyleChange)
242 return foundCombinator ? UseLocalStyleChange : UseSubtreeStyleChange;
244 // We found no features in the sub-selector, only skippable ones (foundIdent was
245 // false at the end of this method). That is a universal selector as far as the
246 // invalidation set is concerned.
247 if (subSelectorMode == UseLocalStyleChange)
248 foundUniversal = true;
250 if (!foundUniversal && !foundCombinator) {
251 // All sub-selectors contained invalidation set features and
252 // we are in the rightmost compound selector.
256 } else if (requiresSubtreeInvalidation(*component)) {
257 return foundCombinator ? UseLocalStyleChange : UseSubtreeStyleChange;
259 if (component->relation() != CSSSelector::SubSelector)
260 foundCombinator = true;
262 return foundIdent ? AddFeatures : UseLocalStyleChange;
265 void RuleFeatureSet::extractInvalidationSetFeature(const CSSSelector& selector, InvalidationSetFeatures& features)
267 if (selector.match() == CSSSelector::Tag)
268 features.tagName = selector.tagQName().localName();
269 else if (selector.match() == CSSSelector::Id)
270 features.id = selector.value();
271 else if (selector.match() == CSSSelector::Class)
272 features.classes.append(selector.value());
273 else if (selector.isAttributeSelector())
274 features.attributes.append(selector.attribute().localName());
275 else if (selector.isCustomPseudoElement())
276 features.customPseudoElement = true;
279 RuleFeatureSet::RuleFeatureSet()
283 RuleFeatureSet::~RuleFeatureSet()
287 DescendantInvalidationSet* RuleFeatureSet::invalidationSetForSelector(const CSSSelector& selector)
289 if (selector.match() == CSSSelector::Class)
290 return &ensureClassInvalidationSet(selector.value());
291 if (selector.isAttributeSelector())
292 return &ensureAttributeInvalidationSet(selector.attribute().localName());
293 if (selector.match() == CSSSelector::Id)
294 return &ensureIdInvalidationSet(selector.value());
295 if (selector.match() == CSSSelector::PseudoClass) {
296 switch (selector.pseudoType()) {
297 case CSSSelector::PseudoEmpty:
298 case CSSSelector::PseudoLink:
299 case CSSSelector::PseudoVisited:
300 case CSSSelector::PseudoAutofill:
301 case CSSSelector::PseudoHover:
302 case CSSSelector::PseudoFocus:
303 case CSSSelector::PseudoActive:
304 case CSSSelector::PseudoChecked:
305 case CSSSelector::PseudoEnabled:
306 case CSSSelector::PseudoDisabled:
307 case CSSSelector::PseudoOptional:
308 case CSSSelector::PseudoRequired:
309 case CSSSelector::PseudoValid:
310 case CSSSelector::PseudoInvalid:
311 case CSSSelector::PseudoIndeterminate:
312 case CSSSelector::PseudoTarget:
313 return &ensurePseudoInvalidationSet(selector.pseudoType());
321 // Given a selector, update the descendant invalidation sets for the features found
322 // in the selector. The first step is to extract the features from the rightmost
323 // compound selector (extractInvalidationSetFeatures). Secondly, those features will be
324 // added to the invalidation sets for the features found in the other compound selectors
325 // (addFeaturesToInvalidationSets).
327 RuleFeatureSet::InvalidationSetMode RuleFeatureSet::updateInvalidationSets(const CSSSelector& selector)
329 InvalidationSetMode mode = invalidationSetModeForSelector(selector);
330 if (mode != AddFeatures)
333 InvalidationSetFeatures features;
334 if (const CSSSelector* current = extractInvalidationSetFeatures(selector, features, false))
335 addFeaturesToInvalidationSets(*current, features);
339 const CSSSelector* RuleFeatureSet::extractInvalidationSetFeatures(const CSSSelector& selector, InvalidationSetFeatures& features, bool negated)
341 for (const CSSSelector* current = &selector; current; current = current->tagHistory()) {
343 extractInvalidationSetFeature(*current, features);
344 // Initialize the entry in the invalidation set map, if supported.
345 invalidationSetForSelector(*current);
346 if (current->pseudoType() == CSSSelector::PseudoHost || current->pseudoType() == CSSSelector::PseudoAny || current->pseudoType() == CSSSelector::PseudoNot) {
347 if (const CSSSelectorList* selectorList = current->selectorList()) {
348 for (const CSSSelector* selector = selectorList->first(); selector; selector = CSSSelectorList::next(*selector))
349 extractInvalidationSetFeatures(*selector, features, current->pseudoType() == CSSSelector::PseudoNot);
353 if (current->relation() == CSSSelector::SubSelector)
356 features.treeBoundaryCrossing = current->isShadowSelector();
357 features.adjacent = current->isAdjacentSelector();
358 return current->tagHistory();
363 // Add features extracted from the rightmost compound selector to descendant invalidation
364 // sets for features found in other compound selectors.
366 // Style invalidation is currently supported for descendants only, not for sibling subtrees.
367 // We use wholeSubtree invalidation for features found left of adjacent combinators as
368 // SubtreeStyleChange will force sibling subtree recalc in
369 // ContainerNode::checkForChildrenAdjacentRuleChanges.
371 // As we encounter a descendant type of combinator, the features only need to be checked
372 // against descendants in the same subtree only. features.adjacent is set to false, and
373 // we start adding features instead of calling setWholeSubtreeInvalid.
375 void RuleFeatureSet::addFeaturesToInvalidationSet(DescendantInvalidationSet& invalidationSet, const InvalidationSetFeatures& features)
377 if (features.treeBoundaryCrossing)
378 invalidationSet.setTreeBoundaryCrossing();
379 if (features.insertionPointCrossing)
380 invalidationSet.setInsertionPointCrossing();
381 if (features.adjacent) {
382 invalidationSet.setWholeSubtreeInvalid();
385 if (!features.id.isEmpty())
386 invalidationSet.addId(features.id);
387 if (!features.tagName.isEmpty())
388 invalidationSet.addTagName(features.tagName);
389 for (const auto& className : features.classes)
390 invalidationSet.addClass(className);
391 for (const auto& attribute : features.attributes)
392 invalidationSet.addAttribute(attribute);
393 if (features.customPseudoElement)
394 invalidationSet.setCustomPseudoInvalid();
397 void RuleFeatureSet::addFeaturesToInvalidationSets(const CSSSelector& selector, InvalidationSetFeatures& features)
399 for (const CSSSelector* current = &selector; current; current = current->tagHistory()) {
400 if (DescendantInvalidationSet* invalidationSet = invalidationSetForSelector(*current)) {
401 addFeaturesToInvalidationSet(*invalidationSet, features);
403 if (current->isTreeBoundaryCrossing())
404 features.treeBoundaryCrossing = true;
405 if (current->isInsertionPointCrossing())
406 features.insertionPointCrossing = true;
407 if (const CSSSelectorList* selectorList = current->selectorList()) {
408 ASSERT(current->pseudoType() == CSSSelector::PseudoHost || current->pseudoType() == CSSSelector::PseudoAny || current->pseudoType() == CSSSelector::PseudoNot);
409 for (const CSSSelector* selector = selectorList->first(); selector; selector = CSSSelectorList::next(*selector))
410 addFeaturesToInvalidationSets(*selector, features);
414 if (current->relation() == CSSSelector::SubSelector)
417 if (current->isShadowSelector())
418 features.treeBoundaryCrossing = true;
420 features.adjacent = current->isAdjacentSelector();
424 void RuleFeatureSet::addContentAttr(const AtomicString& attributeName)
426 ensureAttributeInvalidationSet(attributeName);
429 void RuleFeatureSet::collectFeaturesFromRuleData(const RuleData& ruleData)
431 FeatureMetadata metadata;
432 InvalidationSetMode mode = updateInvalidationSets(ruleData.selector());
434 collectFeaturesFromSelector(ruleData.selector(), metadata, mode);
435 m_metadata.add(metadata);
437 if (metadata.foundSiblingSelector)
438 siblingRules.append(RuleFeature(ruleData.rule(), ruleData.selectorIndex(), ruleData.hasDocumentSecurityOrigin()));
439 if (ruleData.containsUncommonAttributeSelector())
440 uncommonAttributeRules.append(RuleFeature(ruleData.rule(), ruleData.selectorIndex(), ruleData.hasDocumentSecurityOrigin()));
443 DescendantInvalidationSet& RuleFeatureSet::ensureClassInvalidationSet(const AtomicString& className)
445 InvalidationSetMap::AddResult addResult = m_classInvalidationSets.add(className, nullptr);
446 if (addResult.isNewEntry)
447 addResult.storedValue->value = DescendantInvalidationSet::create();
448 return *addResult.storedValue->value;
451 DescendantInvalidationSet& RuleFeatureSet::ensureAttributeInvalidationSet(const AtomicString& attributeName)
453 InvalidationSetMap::AddResult addResult = m_attributeInvalidationSets.add(attributeName, nullptr);
454 if (addResult.isNewEntry)
455 addResult.storedValue->value = DescendantInvalidationSet::create();
456 return *addResult.storedValue->value;
459 DescendantInvalidationSet& RuleFeatureSet::ensureIdInvalidationSet(const AtomicString& id)
461 InvalidationSetMap::AddResult addResult = m_idInvalidationSets.add(id, nullptr);
462 if (addResult.isNewEntry)
463 addResult.storedValue->value = DescendantInvalidationSet::create();
464 return *addResult.storedValue->value;
467 DescendantInvalidationSet& RuleFeatureSet::ensurePseudoInvalidationSet(CSSSelector::PseudoType pseudoType)
469 PseudoTypeInvalidationSetMap::AddResult addResult = m_pseudoInvalidationSets.add(pseudoType, nullptr);
470 if (addResult.isNewEntry)
471 addResult.storedValue->value = DescendantInvalidationSet::create();
472 return *addResult.storedValue->value;
475 void RuleFeatureSet::collectFeaturesFromSelector(const CSSSelector& selector, RuleFeatureSet::FeatureMetadata& metadata, InvalidationSetMode mode)
477 unsigned maxDirectAdjacentSelectors = 0;
479 for (const CSSSelector* current = &selector; current; current = current->tagHistory()) {
480 if (mode != AddFeatures) {
481 if (DescendantInvalidationSet* invalidationSet = invalidationSetForSelector(*current)) {
482 if (mode == UseSubtreeStyleChange)
483 invalidationSet->setWholeSubtreeInvalid();
486 if (current->pseudoType() == CSSSelector::PseudoFirstLine)
487 metadata.usesFirstLineRules = true;
488 if (current->isDirectAdjacentSelector()) {
489 maxDirectAdjacentSelectors++;
490 } else if (maxDirectAdjacentSelectors) {
491 if (maxDirectAdjacentSelectors > metadata.maxDirectAdjacentSelectors)
492 metadata.maxDirectAdjacentSelectors = maxDirectAdjacentSelectors;
493 maxDirectAdjacentSelectors = 0;
495 if (current->isSiblingSelector())
496 metadata.foundSiblingSelector = true;
498 collectFeaturesFromSelectorList(current->selectorList(), metadata, mode);
500 if (mode == UseLocalStyleChange && current->relation() != CSSSelector::SubSelector)
501 mode = UseSubtreeStyleChange;
504 ASSERT(!maxDirectAdjacentSelectors);
507 void RuleFeatureSet::collectFeaturesFromSelectorList(const CSSSelectorList* selectorList, RuleFeatureSet::FeatureMetadata& metadata, InvalidationSetMode mode)
512 for (const CSSSelector* selector = selectorList->first(); selector; selector = CSSSelectorList::next(*selector))
513 collectFeaturesFromSelector(*selector, metadata, mode);
516 void RuleFeatureSet::FeatureMetadata::add(const FeatureMetadata& other)
518 usesFirstLineRules = usesFirstLineRules || other.usesFirstLineRules;
519 maxDirectAdjacentSelectors = std::max(maxDirectAdjacentSelectors, other.maxDirectAdjacentSelectors);
522 void RuleFeatureSet::FeatureMetadata::clear()
524 usesFirstLineRules = false;
525 foundSiblingSelector = false;
526 maxDirectAdjacentSelectors = 0;
529 void RuleFeatureSet::add(const RuleFeatureSet& other)
531 for (const auto& invalidationSet : other.m_classInvalidationSets)
532 ensureClassInvalidationSet(invalidationSet.key).combine(*invalidationSet.value);
533 for (const auto& invalidationSet : other.m_attributeInvalidationSets)
534 ensureAttributeInvalidationSet(invalidationSet.key).combine(*invalidationSet.value);
535 for (const auto& invalidationSet : other.m_idInvalidationSets)
536 ensureIdInvalidationSet(invalidationSet.key).combine(*invalidationSet.value);
537 for (const auto& invalidationSet : other.m_pseudoInvalidationSets)
538 ensurePseudoInvalidationSet(static_cast<CSSSelector::PseudoType>(invalidationSet.key)).combine(*invalidationSet.value);
540 m_metadata.add(other.m_metadata);
542 siblingRules.appendVector(other.siblingRules);
543 uncommonAttributeRules.appendVector(other.uncommonAttributeRules);
546 void RuleFeatureSet::clear()
548 siblingRules.clear();
549 uncommonAttributeRules.clear();
551 m_classInvalidationSets.clear();
552 m_attributeInvalidationSets.clear();
553 m_idInvalidationSets.clear();
554 // We cannot clear m_styleInvalidator here, because the style invalidator might not
555 // have been evaluated yet. If not yet, in StyleInvalidator, there exists some element
556 // who has needsStyleInvlidation but does not have any invalidation list.
557 // This makes Blink not to recalc style correctly. crbug.com/344729.
560 void RuleFeatureSet::scheduleStyleInvalidationForClassChange(const SpaceSplitString& changedClasses, Element& element)
562 unsigned changedSize = changedClasses.size();
563 for (unsigned i = 0; i < changedSize; ++i) {
564 addClassToInvalidationSet(changedClasses[i], element);
568 void RuleFeatureSet::scheduleStyleInvalidationForClassChange(const SpaceSplitString& oldClasses, const SpaceSplitString& newClasses, Element& element)
570 if (!oldClasses.size()) {
571 scheduleStyleInvalidationForClassChange(newClasses, element);
575 // Class vectors tend to be very short. This is faster than using a hash table.
576 BitVector remainingClassBits;
577 remainingClassBits.ensureSize(oldClasses.size());
579 for (unsigned i = 0; i < newClasses.size(); ++i) {
581 for (unsigned j = 0; j < oldClasses.size(); ++j) {
582 if (newClasses[i] == oldClasses[j]) {
583 // Mark each class that is still in the newClasses so we can skip doing
584 // an n^2 search below when looking for removals. We can't break from
585 // this loop early since a class can appear more than once.
586 remainingClassBits.quickSet(j);
592 addClassToInvalidationSet(newClasses[i], element);
595 for (unsigned i = 0; i < oldClasses.size(); ++i) {
596 if (remainingClassBits.quickGet(i))
598 // Class was removed.
599 addClassToInvalidationSet(oldClasses[i], element);
603 void RuleFeatureSet::scheduleStyleInvalidationForAttributeChange(const QualifiedName& attributeName, Element& element)
605 if (RefPtrWillBeRawPtr<DescendantInvalidationSet> invalidationSet = m_attributeInvalidationSets.get(attributeName.localName())) {
606 TRACE_SCHEDULE_STYLE_INVALIDATION(element, *invalidationSet, attributeChange, attributeName);
607 m_styleInvalidator.scheduleInvalidation(invalidationSet, element);
611 void RuleFeatureSet::scheduleStyleInvalidationForIdChange(const AtomicString& oldId, const AtomicString& newId, Element& element)
613 if (!oldId.isEmpty()) {
614 if (RefPtrWillBeRawPtr<DescendantInvalidationSet> invalidationSet = m_idInvalidationSets.get(oldId)) {
615 TRACE_SCHEDULE_STYLE_INVALIDATION(element, *invalidationSet, idChange, oldId);
616 m_styleInvalidator.scheduleInvalidation(invalidationSet, element);
619 if (!newId.isEmpty()) {
620 if (RefPtrWillBeRawPtr<DescendantInvalidationSet> invalidationSet = m_idInvalidationSets.get(newId)) {
621 TRACE_SCHEDULE_STYLE_INVALIDATION(element, *invalidationSet, idChange, newId);
622 m_styleInvalidator.scheduleInvalidation(invalidationSet, element);
627 void RuleFeatureSet::scheduleStyleInvalidationForPseudoChange(CSSSelector::PseudoType pseudo, Element& element)
629 if (RefPtrWillBeRawPtr<DescendantInvalidationSet> invalidationSet = m_pseudoInvalidationSets.get(pseudo)) {
630 TRACE_SCHEDULE_STYLE_INVALIDATION(element, *invalidationSet, pseudoChange, pseudo);
631 m_styleInvalidator.scheduleInvalidation(invalidationSet, element);
635 inline void RuleFeatureSet::addClassToInvalidationSet(const AtomicString& className, Element& element)
637 if (RefPtrWillBeRawPtr<DescendantInvalidationSet> invalidationSet = m_classInvalidationSets.get(className)) {
638 TRACE_SCHEDULE_STYLE_INVALIDATION(element, *invalidationSet, classChange, className);
639 m_styleInvalidator.scheduleInvalidation(invalidationSet, element);
643 StyleInvalidator& RuleFeatureSet::styleInvalidator()
645 return m_styleInvalidator;
648 void RuleFeatureSet::trace(Visitor* visitor)
651 visitor->trace(siblingRules);
652 visitor->trace(uncommonAttributeRules);
653 visitor->trace(m_classInvalidationSets);
654 visitor->trace(m_attributeInvalidationSets);
655 visitor->trace(m_idInvalidationSets);
656 visitor->trace(m_pseudoInvalidationSets);
657 visitor->trace(m_styleInvalidator);