• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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.
12  *
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.
17  *
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.
22  *
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.
27  */
28 
29 #include "config.h"
30 #include "core/css/RuleFeature.h"
31 
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 "platform/RuntimeEnabledFeatures.h"
41 #include "wtf/BitVector.h"
42 
43 namespace WebCore {
44 
isSkippableComponentForInvalidation(const CSSSelector & selector)45 static bool isSkippableComponentForInvalidation(const CSSSelector& selector)
46 {
47     if (selector.match() == CSSSelector::Tag
48         || selector.match() == CSSSelector::Id
49         || selector.isAttributeSelector())
50         return true;
51     if (selector.match() == CSSSelector::PseudoElement) {
52         switch (selector.pseudoType()) {
53         case CSSSelector::PseudoBefore:
54         case CSSSelector::PseudoAfter:
55         case CSSSelector::PseudoBackdrop:
56         case CSSSelector::PseudoShadow:
57             return true;
58         default:
59             return selector.isCustomPseudoElement();
60         }
61     }
62     if (selector.match() != CSSSelector::PseudoClass)
63         return false;
64     switch (selector.pseudoType()) {
65     case CSSSelector::PseudoEmpty:
66     case CSSSelector::PseudoFirstChild:
67     case CSSSelector::PseudoFirstOfType:
68     case CSSSelector::PseudoLastChild:
69     case CSSSelector::PseudoLastOfType:
70     case CSSSelector::PseudoOnlyChild:
71     case CSSSelector::PseudoOnlyOfType:
72     case CSSSelector::PseudoNthChild:
73     case CSSSelector::PseudoNthOfType:
74     case CSSSelector::PseudoNthLastChild:
75     case CSSSelector::PseudoNthLastOfType:
76     case CSSSelector::PseudoLink:
77     case CSSSelector::PseudoVisited:
78     case CSSSelector::PseudoAnyLink:
79     case CSSSelector::PseudoHover:
80     case CSSSelector::PseudoDrag:
81     case CSSSelector::PseudoFocus:
82     case CSSSelector::PseudoActive:
83     case CSSSelector::PseudoChecked:
84     case CSSSelector::PseudoEnabled:
85     case CSSSelector::PseudoDefault:
86     case CSSSelector::PseudoDisabled:
87     case CSSSelector::PseudoOptional:
88     case CSSSelector::PseudoRequired:
89     case CSSSelector::PseudoReadOnly:
90     case CSSSelector::PseudoReadWrite:
91     case CSSSelector::PseudoValid:
92     case CSSSelector::PseudoInvalid:
93     case CSSSelector::PseudoIndeterminate:
94     case CSSSelector::PseudoTarget:
95     case CSSSelector::PseudoLang:
96     case CSSSelector::PseudoRoot:
97     case CSSSelector::PseudoScope:
98     case CSSSelector::PseudoInRange:
99     case CSSSelector::PseudoOutOfRange:
100     case CSSSelector::PseudoUnresolved:
101         return true;
102     default:
103         return false;
104     }
105 }
106 
RuleFeature(StyleRule * rule,unsigned selectorIndex,bool hasDocumentSecurityOrigin)107 RuleFeature::RuleFeature(StyleRule* rule, unsigned selectorIndex, bool hasDocumentSecurityOrigin)
108     : rule(rule)
109     , selectorIndex(selectorIndex)
110     , hasDocumentSecurityOrigin(hasDocumentSecurityOrigin)
111 {
112 }
113 
trace(Visitor * visitor)114 void RuleFeature::trace(Visitor* visitor)
115 {
116     visitor->trace(rule);
117 }
118 
119 // This method is somewhat conservative in what it accepts.
invalidationSetModeForSelector(const CSSSelector & selector)120 RuleFeatureSet::InvalidationSetMode RuleFeatureSet::invalidationSetModeForSelector(const CSSSelector& selector)
121 {
122     bool foundDescendantRelation = false;
123     bool foundIdent = false;
124     for (const CSSSelector* component = &selector; component; component = component->tagHistory()) {
125 
126         if (component->match() == CSSSelector::Class || component->match() == CSSSelector::Id
127             || (component->match() == CSSSelector::Tag && component->tagQName().localName() != starAtom)
128             || component->isAttributeSelector() || component->isCustomPseudoElement()) {
129             if (!foundDescendantRelation)
130                 foundIdent = true;
131         } else if (component->pseudoType() == CSSSelector::PseudoHost || component->pseudoType() == CSSSelector::PseudoAny) {
132             if (const CSSSelectorList* selectorList = component->selectorList()) {
133                 for (const CSSSelector* selector = selectorList->first(); selector; selector = CSSSelectorList::next(*selector)) {
134                     InvalidationSetMode hostMode = invalidationSetModeForSelector(*selector);
135                     if (hostMode == UseSubtreeStyleChange)
136                         return foundDescendantRelation ? UseLocalStyleChange : UseSubtreeStyleChange;
137                     if (!foundDescendantRelation && hostMode == AddFeatures)
138                         foundIdent = true;
139                 }
140             }
141         } else if (!isSkippableComponentForInvalidation(*component)) {
142             return foundDescendantRelation ? UseLocalStyleChange : UseSubtreeStyleChange;
143         }
144         switch (component->relation()) {
145         case CSSSelector::Descendant:
146         case CSSSelector::Child:
147         case CSSSelector::ShadowPseudo:
148         case CSSSelector::ShadowDeep:
149             foundDescendantRelation = true;
150             // Fall through!
151         case CSSSelector::SubSelector:
152         case CSSSelector::DirectAdjacent:
153         case CSSSelector::IndirectAdjacent:
154             continue;
155         default:
156             // All combinators should be handled above.
157             ASSERT_NOT_REACHED();
158             return UseLocalStyleChange;
159         }
160     }
161     return foundIdent ? AddFeatures : UseLocalStyleChange;
162 }
163 
extractInvalidationSetFeature(const CSSSelector & selector,InvalidationSetFeatures & features)164 void RuleFeatureSet::extractInvalidationSetFeature(const CSSSelector& selector, InvalidationSetFeatures& features)
165 {
166     if (selector.match() == CSSSelector::Tag)
167         features.tagName = selector.tagQName().localName();
168     else if (selector.match() == CSSSelector::Id)
169         features.id = selector.value();
170     else if (selector.match() == CSSSelector::Class)
171         features.classes.append(selector.value());
172     else if (selector.isAttributeSelector())
173         features.attributes.append(selector.attribute().localName());
174     else if (selector.isCustomPseudoElement())
175         features.customPseudoElement = true;
176 }
177 
RuleFeatureSet()178 RuleFeatureSet::RuleFeatureSet()
179     : m_targetedStyleRecalcEnabled(RuntimeEnabledFeatures::targetedStyleRecalcEnabled())
180 {
181 }
182 
~RuleFeatureSet()183 RuleFeatureSet::~RuleFeatureSet()
184 {
185 }
186 
invalidationSetForSelector(const CSSSelector & selector)187 DescendantInvalidationSet* RuleFeatureSet::invalidationSetForSelector(const CSSSelector& selector)
188 {
189     if (selector.match() == CSSSelector::Class)
190         return &ensureClassInvalidationSet(selector.value());
191     if (selector.isAttributeSelector())
192         return &ensureAttributeInvalidationSet(selector.attribute().localName());
193     if (selector.match() == CSSSelector::Id)
194         return &ensureIdInvalidationSet(selector.value());
195     if (selector.match() == CSSSelector::PseudoClass) {
196         CSSSelector::PseudoType pseudo = selector.pseudoType();
197         if (pseudo == CSSSelector::PseudoHover || pseudo == CSSSelector::PseudoActive || pseudo == CSSSelector::PseudoFocus)
198             return &ensurePseudoInvalidationSet(pseudo);
199     }
200     return 0;
201 }
202 
updateInvalidationSets(const CSSSelector & selector)203 RuleFeatureSet::InvalidationSetMode RuleFeatureSet::updateInvalidationSets(const CSSSelector& selector)
204 {
205     InvalidationSetMode mode = invalidationSetModeForSelector(selector);
206     if (mode != AddFeatures)
207         return mode;
208 
209     InvalidationSetFeatures features;
210     if (const CSSSelector* current = extractInvalidationSetFeatures(selector, features))
211         addFeaturesToInvalidationSets(*current, features);
212     return AddFeatures;
213 }
214 
extractInvalidationSetFeatures(const CSSSelector & selector,InvalidationSetFeatures & features)215 const CSSSelector* RuleFeatureSet::extractInvalidationSetFeatures(const CSSSelector& selector, InvalidationSetFeatures& features)
216 {
217     for (const CSSSelector* current = &selector; current; current = current->tagHistory()) {
218         extractInvalidationSetFeature(*current, features);
219         // Initialize the entry in the invalidation set map, if supported.
220         invalidationSetForSelector(*current);
221         if (current->pseudoType() == CSSSelector::PseudoHost || current->pseudoType() == CSSSelector::PseudoAny) {
222             if (const CSSSelectorList* selectorList = current->selectorList()) {
223                 for (const CSSSelector* selector = selectorList->first(); selector; selector = CSSSelectorList::next(*selector))
224                     extractInvalidationSetFeatures(*selector, features);
225             }
226         }
227 
228         switch (current->relation()) {
229         case CSSSelector::SubSelector:
230             break;
231         case CSSSelector::ShadowPseudo:
232         case CSSSelector::ShadowDeep:
233             features.treeBoundaryCrossing = true;
234             return current->tagHistory();
235         case CSSSelector::DirectAdjacent:
236         case CSSSelector::IndirectAdjacent:
237             features.wholeSubtree = true;
238             return current->tagHistory();
239         case CSSSelector::Descendant:
240         case CSSSelector::Child:
241             return current->tagHistory();
242         }
243     }
244     return 0;
245 }
246 
addFeaturesToInvalidationSets(const CSSSelector & selector,InvalidationSetFeatures & features)247 void RuleFeatureSet::addFeaturesToInvalidationSets(const CSSSelector& selector, InvalidationSetFeatures& features)
248 {
249     for (const CSSSelector* current = &selector; current; current = current->tagHistory()) {
250         if (DescendantInvalidationSet* invalidationSet = invalidationSetForSelector(*current)) {
251             if (features.treeBoundaryCrossing)
252                 invalidationSet->setTreeBoundaryCrossing();
253             if (features.wholeSubtree) {
254                 invalidationSet->setWholeSubtreeInvalid();
255             } else {
256                 if (!features.id.isEmpty())
257                     invalidationSet->addId(features.id);
258                 if (!features.tagName.isEmpty())
259                     invalidationSet->addTagName(features.tagName);
260                 for (Vector<AtomicString>::const_iterator it = features.classes.begin(); it != features.classes.end(); ++it)
261                     invalidationSet->addClass(*it);
262                 for (Vector<AtomicString>::const_iterator it = features.attributes.begin(); it != features.attributes.end(); ++it)
263                     invalidationSet->addAttribute(*it);
264                 if (features.customPseudoElement)
265                     invalidationSet->setCustomPseudoInvalid();
266             }
267         } else if (current->pseudoType() == CSSSelector::PseudoHost || current->pseudoType() == CSSSelector::PseudoAny) {
268             if (current->pseudoType() == CSSSelector::PseudoHost)
269                 features.treeBoundaryCrossing = true;
270             if (const CSSSelectorList* selectorList = current->selectorList()) {
271                 for (const CSSSelector* selector = selectorList->first(); selector; selector = CSSSelectorList::next(*selector))
272                     addFeaturesToInvalidationSets(*selector, features);
273             }
274         }
275         switch (current->relation()) {
276         case CSSSelector::SubSelector:
277             break;
278         case CSSSelector::ShadowPseudo:
279         case CSSSelector::ShadowDeep:
280             features.treeBoundaryCrossing = true;
281             features.wholeSubtree = false;
282             break;
283         case CSSSelector::Descendant:
284         case CSSSelector::Child:
285             features.wholeSubtree = false;
286             break;
287         case CSSSelector::DirectAdjacent:
288         case CSSSelector::IndirectAdjacent:
289             features.wholeSubtree = true;
290             break;
291         }
292     }
293 }
294 
addContentAttr(const AtomicString & attributeName)295 void RuleFeatureSet::addContentAttr(const AtomicString& attributeName)
296 {
297     DescendantInvalidationSet& invalidationSet = ensureAttributeInvalidationSet(attributeName);
298     invalidationSet.setWholeSubtreeInvalid();
299 }
300 
collectFeaturesFromRuleData(const RuleData & ruleData)301 void RuleFeatureSet::collectFeaturesFromRuleData(const RuleData& ruleData)
302 {
303     FeatureMetadata metadata;
304     InvalidationSetMode mode = UseSubtreeStyleChange;
305     if (m_targetedStyleRecalcEnabled)
306         mode = updateInvalidationSets(ruleData.selector());
307 
308     collectFeaturesFromSelector(ruleData.selector(), metadata, mode);
309     m_metadata.add(metadata);
310 
311     if (metadata.foundSiblingSelector)
312         siblingRules.append(RuleFeature(ruleData.rule(), ruleData.selectorIndex(), ruleData.hasDocumentSecurityOrigin()));
313     if (ruleData.containsUncommonAttributeSelector())
314         uncommonAttributeRules.append(RuleFeature(ruleData.rule(), ruleData.selectorIndex(), ruleData.hasDocumentSecurityOrigin()));
315 }
316 
ensureClassInvalidationSet(const AtomicString & className)317 DescendantInvalidationSet& RuleFeatureSet::ensureClassInvalidationSet(const AtomicString& className)
318 {
319     InvalidationSetMap::AddResult addResult = m_classInvalidationSets.add(className, nullptr);
320     if (addResult.isNewEntry)
321         addResult.storedValue->value = DescendantInvalidationSet::create();
322     return *addResult.storedValue->value;
323 }
324 
ensureAttributeInvalidationSet(const AtomicString & attributeName)325 DescendantInvalidationSet& RuleFeatureSet::ensureAttributeInvalidationSet(const AtomicString& attributeName)
326 {
327     InvalidationSetMap::AddResult addResult = m_attributeInvalidationSets.add(attributeName, nullptr);
328     if (addResult.isNewEntry)
329         addResult.storedValue->value = DescendantInvalidationSet::create();
330     return *addResult.storedValue->value;
331 }
332 
ensureIdInvalidationSet(const AtomicString & id)333 DescendantInvalidationSet& RuleFeatureSet::ensureIdInvalidationSet(const AtomicString& id)
334 {
335     InvalidationSetMap::AddResult addResult = m_idInvalidationSets.add(id, nullptr);
336     if (addResult.isNewEntry)
337         addResult.storedValue->value = DescendantInvalidationSet::create();
338     return *addResult.storedValue->value;
339 }
340 
ensurePseudoInvalidationSet(CSSSelector::PseudoType pseudoType)341 DescendantInvalidationSet& RuleFeatureSet::ensurePseudoInvalidationSet(CSSSelector::PseudoType pseudoType)
342 {
343     PseudoTypeInvalidationSetMap::AddResult addResult = m_pseudoInvalidationSets.add(pseudoType, nullptr);
344     if (addResult.isNewEntry)
345         addResult.storedValue->value = DescendantInvalidationSet::create();
346     return *addResult.storedValue->value;
347 }
348 
collectFeaturesFromSelector(const CSSSelector & selector)349 void RuleFeatureSet::collectFeaturesFromSelector(const CSSSelector& selector)
350 {
351     collectFeaturesFromSelector(selector, m_metadata, UseSubtreeStyleChange);
352 }
353 
collectFeaturesFromSelector(const CSSSelector & selector,RuleFeatureSet::FeatureMetadata & metadata,InvalidationSetMode mode)354 void RuleFeatureSet::collectFeaturesFromSelector(const CSSSelector& selector, RuleFeatureSet::FeatureMetadata& metadata, InvalidationSetMode mode)
355 {
356     unsigned maxDirectAdjacentSelectors = 0;
357 
358     for (const CSSSelector* current = &selector; current; current = current->tagHistory()) {
359         if (mode != AddFeatures) {
360             if (DescendantInvalidationSet* invalidationSet = invalidationSetForSelector(*current)) {
361                 if (mode == UseSubtreeStyleChange)
362                     invalidationSet->setWholeSubtreeInvalid();
363             }
364         }
365         if (current->pseudoType() == CSSSelector::PseudoFirstLine)
366             metadata.usesFirstLineRules = true;
367         if (current->isDirectAdjacentSelector()) {
368             maxDirectAdjacentSelectors++;
369         } else if (maxDirectAdjacentSelectors) {
370             if (maxDirectAdjacentSelectors > metadata.maxDirectAdjacentSelectors)
371                 metadata.maxDirectAdjacentSelectors = maxDirectAdjacentSelectors;
372             maxDirectAdjacentSelectors = 0;
373         }
374         if (current->isSiblingSelector())
375             metadata.foundSiblingSelector = true;
376 
377         collectFeaturesFromSelectorList(current->selectorList(), metadata, mode);
378 
379         if (mode == UseLocalStyleChange && current->relation() != CSSSelector::SubSelector)
380             mode = UseSubtreeStyleChange;
381     }
382 
383     ASSERT(!maxDirectAdjacentSelectors);
384 }
385 
collectFeaturesFromSelectorList(const CSSSelectorList * selectorList,RuleFeatureSet::FeatureMetadata & metadata,InvalidationSetMode mode)386 void RuleFeatureSet::collectFeaturesFromSelectorList(const CSSSelectorList* selectorList, RuleFeatureSet::FeatureMetadata& metadata, InvalidationSetMode mode)
387 {
388     if (!selectorList)
389         return;
390 
391     for (const CSSSelector* selector = selectorList->first(); selector; selector = CSSSelectorList::next(*selector))
392         collectFeaturesFromSelector(*selector, metadata, mode);
393 }
394 
add(const FeatureMetadata & other)395 void RuleFeatureSet::FeatureMetadata::add(const FeatureMetadata& other)
396 {
397     usesFirstLineRules = usesFirstLineRules || other.usesFirstLineRules;
398     maxDirectAdjacentSelectors = std::max(maxDirectAdjacentSelectors, other.maxDirectAdjacentSelectors);
399 }
400 
clear()401 void RuleFeatureSet::FeatureMetadata::clear()
402 {
403     usesFirstLineRules = false;
404     foundSiblingSelector = false;
405     maxDirectAdjacentSelectors = 0;
406 }
407 
add(const RuleFeatureSet & other)408 void RuleFeatureSet::add(const RuleFeatureSet& other)
409 {
410     for (InvalidationSetMap::const_iterator it = other.m_classInvalidationSets.begin(); it != other.m_classInvalidationSets.end(); ++it)
411         ensureClassInvalidationSet(it->key).combine(*it->value);
412     for (InvalidationSetMap::const_iterator it = other.m_attributeInvalidationSets.begin(); it != other.m_attributeInvalidationSets.end(); ++it)
413         ensureAttributeInvalidationSet(it->key).combine(*it->value);
414     for (InvalidationSetMap::const_iterator it = other.m_idInvalidationSets.begin(); it != other.m_idInvalidationSets.end(); ++it)
415         ensureIdInvalidationSet(it->key).combine(*it->value);
416     for (PseudoTypeInvalidationSetMap::const_iterator it = other.m_pseudoInvalidationSets.begin(); it != other.m_pseudoInvalidationSets.end(); ++it)
417         ensurePseudoInvalidationSet(static_cast<CSSSelector::PseudoType>(it->key)).combine(*it->value);
418 
419     m_metadata.add(other.m_metadata);
420 
421     siblingRules.appendVector(other.siblingRules);
422     uncommonAttributeRules.appendVector(other.uncommonAttributeRules);
423 }
424 
clear()425 void RuleFeatureSet::clear()
426 {
427     siblingRules.clear();
428     uncommonAttributeRules.clear();
429     m_metadata.clear();
430     m_classInvalidationSets.clear();
431     m_attributeInvalidationSets.clear();
432     m_idInvalidationSets.clear();
433     // We cannot clear m_styleInvalidator here, because the style invalidator might not
434     // have been evaluated yet. If not yet, in StyleInvalidator, there exists some element
435     // who has needsStyleInvlidation but does not have any invalidation list.
436     // This makes Blink not to recalc style correctly. crbug.com/344729.
437 }
438 
scheduleStyleInvalidationForClassChange(const SpaceSplitString & changedClasses,Element & element)439 void RuleFeatureSet::scheduleStyleInvalidationForClassChange(const SpaceSplitString& changedClasses, Element& element)
440 {
441     unsigned changedSize = changedClasses.size();
442     for (unsigned i = 0; i < changedSize; ++i) {
443         addClassToInvalidationSet(changedClasses[i], element);
444     }
445 }
446 
scheduleStyleInvalidationForClassChange(const SpaceSplitString & oldClasses,const SpaceSplitString & newClasses,Element & element)447 void RuleFeatureSet::scheduleStyleInvalidationForClassChange(const SpaceSplitString& oldClasses, const SpaceSplitString& newClasses, Element& element)
448 {
449     if (!oldClasses.size()) {
450         scheduleStyleInvalidationForClassChange(newClasses, element);
451         return;
452     }
453 
454     // Class vectors tend to be very short. This is faster than using a hash table.
455     BitVector remainingClassBits;
456     remainingClassBits.ensureSize(oldClasses.size());
457 
458     for (unsigned i = 0; i < newClasses.size(); ++i) {
459         bool found = false;
460         for (unsigned j = 0; j < oldClasses.size(); ++j) {
461             if (newClasses[i] == oldClasses[j]) {
462                 // Mark each class that is still in the newClasses so we can skip doing
463                 // an n^2 search below when looking for removals. We can't break from
464                 // this loop early since a class can appear more than once.
465                 remainingClassBits.quickSet(j);
466                 found = true;
467             }
468         }
469         // Class was added.
470         if (!found)
471             addClassToInvalidationSet(newClasses[i], element);
472     }
473 
474     for (unsigned i = 0; i < oldClasses.size(); ++i) {
475         if (remainingClassBits.quickGet(i))
476             continue;
477         // Class was removed.
478         addClassToInvalidationSet(oldClasses[i], element);
479     }
480 }
481 
scheduleStyleInvalidationForAttributeChange(const QualifiedName & attributeName,Element & element)482 void RuleFeatureSet::scheduleStyleInvalidationForAttributeChange(const QualifiedName& attributeName, Element& element)
483 {
484 
485     if (RefPtrWillBeRawPtr<DescendantInvalidationSet> invalidationSet = m_attributeInvalidationSets.get(attributeName.localName()))
486         m_styleInvalidator.scheduleInvalidation(invalidationSet, element);
487 }
488 
scheduleStyleInvalidationForIdChange(const AtomicString & oldId,const AtomicString & newId,Element & element)489 void RuleFeatureSet::scheduleStyleInvalidationForIdChange(const AtomicString& oldId, const AtomicString& newId, Element& element)
490 {
491     if (!oldId.isEmpty()) {
492         if (RefPtrWillBeRawPtr<DescendantInvalidationSet> invalidationSet = m_idInvalidationSets.get(oldId))
493             m_styleInvalidator.scheduleInvalidation(invalidationSet, element);
494     }
495     if (!newId.isEmpty()) {
496         if (RefPtrWillBeRawPtr<DescendantInvalidationSet> invalidationSet = m_idInvalidationSets.get(newId))
497             m_styleInvalidator.scheduleInvalidation(invalidationSet, element);
498     }
499 }
500 
scheduleStyleInvalidationForPseudoChange(CSSSelector::PseudoType pseudo,Element & element)501 void RuleFeatureSet::scheduleStyleInvalidationForPseudoChange(CSSSelector::PseudoType pseudo, Element& element)
502 {
503     if (RefPtrWillBeRawPtr<DescendantInvalidationSet> invalidationSet = m_pseudoInvalidationSets.get(pseudo))
504         m_styleInvalidator.scheduleInvalidation(invalidationSet, element);
505 }
506 
addClassToInvalidationSet(const AtomicString & className,Element & element)507 void RuleFeatureSet::addClassToInvalidationSet(const AtomicString& className, Element& element)
508 {
509     if (RefPtrWillBeRawPtr<DescendantInvalidationSet> invalidationSet = m_classInvalidationSets.get(className))
510         m_styleInvalidator.scheduleInvalidation(invalidationSet, element);
511 }
512 
styleInvalidator()513 StyleInvalidator& RuleFeatureSet::styleInvalidator()
514 {
515     return m_styleInvalidator;
516 }
517 
trace(Visitor * visitor)518 void RuleFeatureSet::trace(Visitor* visitor)
519 {
520     visitor->trace(siblingRules);
521     visitor->trace(uncommonAttributeRules);
522     visitor->trace(m_classInvalidationSets);
523     visitor->trace(m_attributeInvalidationSets);
524     visitor->trace(m_idInvalidationSets);
525     visitor->trace(m_pseudoInvalidationSets);
526     visitor->trace(m_styleInvalidator);
527 }
528 
529 } // namespace WebCore
530