| 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 15 matching lines...) Expand all Loading... |
| 26 * Boston, MA 02110-1301, USA. | 26 * Boston, MA 02110-1301, USA. |
| 27 */ | 27 */ |
| 28 | 28 |
| 29 #include "config.h" | 29 #include "config.h" |
| 30 #include "core/css/RuleFeature.h" | 30 #include "core/css/RuleFeature.h" |
| 31 | 31 |
| 32 #include "core/css/CSSSelector.h" | 32 #include "core/css/CSSSelector.h" |
| 33 #include "core/css/CSSSelectorList.h" | 33 #include "core/css/CSSSelectorList.h" |
| 34 #include "core/css/RuleSet.h" | 34 #include "core/css/RuleSet.h" |
| 35 #include "core/css/StyleRule.h" | 35 #include "core/css/StyleRule.h" |
| 36 #include "core/css/invalidation/DescendantInvalidationSet.h" | |
| 37 #include "core/dom/Element.h" | 36 #include "core/dom/Element.h" |
| 38 #include "core/dom/Node.h" | 37 #include "core/dom/Node.h" |
| 39 #include "platform/RuntimeEnabledFeatures.h" | |
| 40 #include "wtf/BitVector.h" | 38 #include "wtf/BitVector.h" |
| 41 | 39 |
| 42 namespace blink { | 40 namespace blink { |
| 43 | 41 |
| 44 static bool isSkippableComponentForInvalidation(const CSSSelector& selector) | 42 RuleFeatureSet::RuleFeatureSet() |
| 45 { | |
| 46 if (selector.match() == CSSSelector::Tag) { | |
| 47 ASSERT(selector.tagQName().localName() == starAtom); | |
| 48 return true; | |
| 49 } | |
| 50 if (selector.match() == CSSSelector::PseudoElement) | |
| 51 return false; | |
| 52 if (selector.match() != CSSSelector::PseudoClass) | |
| 53 return false; | |
| 54 switch (selector.pseudoType()) { | |
| 55 case CSSSelector::PseudoHover: | |
| 56 case CSSSelector::PseudoFocus: | |
| 57 case CSSSelector::PseudoActive: | |
| 58 case CSSSelector::PseudoLang: | |
| 59 case CSSSelector::PseudoUnresolved: | |
| 60 return true; | |
| 61 default: | |
| 62 return false; | |
| 63 } | |
| 64 } | |
| 65 | |
| 66 RuleFeature::RuleFeature(StyleRule* rule, unsigned selectorIndex) | |
| 67 : rule(rule) | |
| 68 , selectorIndex(selectorIndex) | |
| 69 { | 43 { |
| 70 } | 44 } |
| 71 | 45 |
| 72 void RuleFeature::trace(Visitor* visitor) | |
| 73 { | |
| 74 visitor->trace(rule); | |
| 75 } | |
| 76 | |
| 77 // This method is somewhat conservative in what it accepts. | |
| 78 RuleFeatureSet::InvalidationSetMode RuleFeatureSet::invalidationSetModeForSelect
or(const CSSSelector& selector) | |
| 79 { | |
| 80 bool foundCombinator = false; | |
| 81 bool foundIdent = false; | |
| 82 for (const CSSSelector* component = &selector; component; component = compon
ent->tagHistory()) { | |
| 83 | |
| 84 if (component->match() == CSSSelector::Class || component->match() == CS
SSelector::Id | |
| 85 || (component->match() == CSSSelector::Tag && component->tagQName().
localName() != starAtom) | |
| 86 || component->isAttributeSelector() || component->isCustomPseudoElem
ent()) { | |
| 87 if (!foundCombinator) { | |
| 88 // We have found an invalidation set feature in the rightmost co
mpound selector. | |
| 89 foundIdent = true; | |
| 90 } | |
| 91 } else if (component->pseudoType() == CSSSelector::PseudoHost) { | |
| 92 if (const CSSSelectorList* selectorList = component->selectorList())
{ | |
| 93 // Features inside :not() are not added to the feature set, so c
onsider it a universal selector. | |
| 94 bool foundUniversal = false; | |
| 95 for (const CSSSelector* selector = selectorList->first(); select
or; selector = CSSSelectorList::next(*selector)) { | |
| 96 // Find the invalidation set mode for each of the selectors
in the selector list | |
| 97 // of a :not(), :host(), etc. For instance, ".x :-webkit-any
(.a, .b)" yields an | |
| 98 // AddFeatures mode for both ".a" and ".b". ":-webkit-any(.a
, *)" yields AddFeatures | |
| 99 // for ".a", but UseSubtreeStyleChange for "*". One sub-sele
ctor without invalidation | |
| 100 // set features is sufficient to cause the selector to be a
universal selector as far | |
| 101 // the invalidation set is concerned. | |
| 102 InvalidationSetMode subSelectorMode = invalidationSetModeFor
Selector(*selector); | |
| 103 | |
| 104 // The sub-selector contained something unskippable, fall ba
ck to whole subtree | |
| 105 // recalcs in collectFeaturesFromSelector. subSelectorMode w
ill return | |
| 106 // UseSubtreeStyleChange since there are no combinators insi
de the selector list, | |
| 107 // so translate it to UseLocalStyleChange if a combinator ha
s been seen in the | |
| 108 // outer context. | |
| 109 // | |
| 110 // FIXME: Is UseSubtreeStyleChange ever needed as input to c
ollectFeaturesFromSelector? | |
| 111 // That is, are there any selectors for which we need to use
SubtreeStyleChange for | |
| 112 // changing features when present in the rightmost compound
selector? | |
| 113 if (subSelectorMode == UseSubtreeStyleChange) | |
| 114 return foundCombinator ? UseLocalStyleChange : UseSubtre
eStyleChange; | |
| 115 | |
| 116 // We found no features in the sub-selector, only skippable
ones (foundIdent was | |
| 117 // false at the end of this method). That is a universal sel
ector as far as the | |
| 118 // invalidation set is concerned. | |
| 119 if (subSelectorMode == UseLocalStyleChange) | |
| 120 foundUniversal = true; | |
| 121 } | |
| 122 if (!foundUniversal && !foundCombinator) { | |
| 123 // All sub-selectors contained invalidation set features and | |
| 124 // we are in the rightmost compound selector. | |
| 125 foundIdent = true; | |
| 126 } | |
| 127 } | |
| 128 } else if (!isSkippableComponentForInvalidation(*component)) { | |
| 129 return foundCombinator ? UseLocalStyleChange : UseSubtreeStyleChange
; | |
| 130 } | |
| 131 foundCombinator = true; | |
| 132 } | |
| 133 return foundIdent ? AddFeatures : UseLocalStyleChange; | |
| 134 } | |
| 135 | |
| 136 void RuleFeatureSet::extractInvalidationSetFeature(const CSSSelector& selector,
InvalidationSetFeatures& features) | |
| 137 { | |
| 138 if (selector.match() == CSSSelector::Tag) | |
| 139 features.tagName = selector.tagQName().localName(); | |
| 140 else if (selector.match() == CSSSelector::Id) | |
| 141 features.id = selector.value(); | |
| 142 else if (selector.match() == CSSSelector::Class) | |
| 143 features.classes.append(selector.value()); | |
| 144 else if (selector.isAttributeSelector()) | |
| 145 features.attributes.append(selector.attribute().localName()); | |
| 146 else if (selector.isCustomPseudoElement()) | |
| 147 features.customPseudoElement = true; | |
| 148 } | |
| 149 | |
| 150 RuleFeatureSet::RuleFeatureSet() | |
| 151 : m_targetedStyleRecalcEnabled(RuntimeEnabledFeatures::targetedStyleRecalcEn
abled()) | |
| 152 { | |
| 153 } | |
| 154 | |
| 155 RuleFeatureSet::~RuleFeatureSet() | 46 RuleFeatureSet::~RuleFeatureSet() |
| 156 { | 47 { |
| 157 } | 48 } |
| 158 | 49 |
| 159 DescendantInvalidationSet* RuleFeatureSet::invalidationSetForSelector(const CSSS
elector& selector) | 50 void RuleFeatureSet::addSelectorFeatures(const CSSSelector& selector) |
| 160 { | 51 { |
| 161 if (selector.match() == CSSSelector::Class) | 52 if (selector.match() == CSSSelector::Class) |
| 162 return &ensureClassInvalidationSet(selector.value()); | 53 m_classNames.add(selector.value()); |
| 163 if (selector.isAttributeSelector()) | 54 else if (selector.match() == CSSSelector::Id) |
| 164 return &ensureAttributeInvalidationSet(selector.attribute().localName())
; | 55 m_idNames.add(selector.value()); |
| 165 if (selector.match() == CSSSelector::Id) | 56 else if (selector.isAttributeSelector()) |
| 166 return &ensureIdInvalidationSet(selector.value()); | 57 m_attributeNames.add(selector.attribute().localName()); |
| 167 if (selector.match() == CSSSelector::PseudoClass) { | |
| 168 CSSSelector::PseudoType pseudo = selector.pseudoType(); | |
| 169 if (pseudo == CSSSelector::PseudoHover || pseudo == CSSSelector::PseudoA
ctive || pseudo == CSSSelector::PseudoFocus) | |
| 170 return &ensurePseudoInvalidationSet(pseudo); | |
| 171 } | |
| 172 return 0; | |
| 173 } | |
| 174 | |
| 175 // Given a selector, update the descendant invalidation sets for the features fo
und | |
| 176 // in the selector. The first step is to extract the features from the rightmost | |
| 177 // compound selector (extractInvalidationSetFeatures). Secondly, those features
will be | |
| 178 // added to the invalidation sets for the features found in the other compound s
electors | |
| 179 // (addFeaturesToInvalidationSets). | |
| 180 | |
| 181 RuleFeatureSet::InvalidationSetMode RuleFeatureSet::updateInvalidationSets(const
CSSSelector& selector) | |
| 182 { | |
| 183 InvalidationSetMode mode = invalidationSetModeForSelector(selector); | |
| 184 if (mode != AddFeatures) | |
| 185 return mode; | |
| 186 | |
| 187 InvalidationSetFeatures features; | |
| 188 if (const CSSSelector* current = extractInvalidationSetFeatures(selector, fe
atures, false)) | |
| 189 addFeaturesToInvalidationSets(*current, features); | |
| 190 return AddFeatures; | |
| 191 } | |
| 192 | |
| 193 const CSSSelector* RuleFeatureSet::extractInvalidationSetFeatures(const CSSSelec
tor& selector, InvalidationSetFeatures& features, bool negated) | |
| 194 { | |
| 195 for (const CSSSelector* current = &selector; current; current = current->tag
History()) { | |
| 196 if (!negated) | |
| 197 extractInvalidationSetFeature(*current, features); | |
| 198 // Initialize the entry in the invalidation set map, if supported. | |
| 199 invalidationSetForSelector(*current); | |
| 200 if (current->pseudoType() == CSSSelector::PseudoHost) { | |
| 201 if (const CSSSelectorList* selectorList = current->selectorList()) { | |
| 202 for (const CSSSelector* selector = selectorList->first(); select
or; selector = CSSSelectorList::next(*selector)) | |
| 203 extractInvalidationSetFeatures(*selector, features, false); | |
| 204 } | |
| 205 } | |
| 206 } | |
| 207 return 0; | |
| 208 } | |
| 209 | |
| 210 // Add features extracted from the rightmost compound selector to descendant inv
alidation | |
| 211 // sets for features found in other compound selectors. | |
| 212 // | |
| 213 // As we encounter a descendant type of combinator, the features only need to be
checked | |
| 214 // against descendants in the same subtree only. Hence wholeSubtree is reset to
false. | |
| 215 | |
| 216 void RuleFeatureSet::addFeaturesToInvalidationSets(const CSSSelector& selector,
InvalidationSetFeatures& features) | |
| 217 { | |
| 218 for (const CSSSelector* current = &selector; current; current = current->tag
History()) { | |
| 219 if (DescendantInvalidationSet* invalidationSet = invalidationSetForSelec
tor(*current)) { | |
| 220 if (features.treeBoundaryCrossing) | |
| 221 invalidationSet->setTreeBoundaryCrossing(); | |
| 222 if (features.wholeSubtree) { | |
| 223 invalidationSet->setWholeSubtreeInvalid(); | |
| 224 } else { | |
| 225 if (!features.id.isEmpty()) | |
| 226 invalidationSet->addId(features.id); | |
| 227 if (!features.tagName.isEmpty()) | |
| 228 invalidationSet->addTagName(features.tagName); | |
| 229 for (Vector<AtomicString>::const_iterator it = features.classes.
begin(); it != features.classes.end(); ++it) | |
| 230 invalidationSet->addClass(*it); | |
| 231 for (Vector<AtomicString>::const_iterator it = features.attribut
es.begin(); it != features.attributes.end(); ++it) | |
| 232 invalidationSet->addAttribute(*it); | |
| 233 if (features.customPseudoElement) | |
| 234 invalidationSet->setCustomPseudoInvalid(); | |
| 235 } | |
| 236 } else { | |
| 237 if (current->pseudoType() == CSSSelector::PseudoHost) | |
| 238 features.treeBoundaryCrossing = true; | |
| 239 if (const CSSSelectorList* selectorList = current->selectorList()) { | |
| 240 ASSERT(current->pseudoType() == CSSSelector::PseudoHost); | |
| 241 for (const CSSSelector* selector = selectorList->first(); select
or; selector = CSSSelectorList::next(*selector)) | |
| 242 addFeaturesToInvalidationSets(*selector, features); | |
| 243 } | |
| 244 } | |
| 245 } | |
| 246 } | |
| 247 | |
| 248 void RuleFeatureSet::addContentAttr(const AtomicString& attributeName) | |
| 249 { | |
| 250 DescendantInvalidationSet& invalidationSet = ensureAttributeInvalidationSet(
attributeName); | |
| 251 invalidationSet.setWholeSubtreeInvalid(); | |
| 252 } | 58 } |
| 253 | 59 |
| 254 void RuleFeatureSet::collectFeaturesFromRuleData(const RuleData& ruleData) | 60 void RuleFeatureSet::collectFeaturesFromRuleData(const RuleData& ruleData) |
| 255 { | 61 { |
| 256 InvalidationSetMode mode = UseSubtreeStyleChange; | 62 collectFeaturesFromSelector(ruleData.selector()); |
| 257 if (m_targetedStyleRecalcEnabled) | |
| 258 mode = updateInvalidationSets(ruleData.selector()); | |
| 259 | |
| 260 collectFeaturesFromSelector(ruleData.selector(), mode); | |
| 261 | 63 |
| 262 if (ruleData.containsAttributeSelector()) | 64 if (ruleData.containsAttributeSelector()) |
| 263 attributeRules.append(RuleFeature(ruleData.rule(), ruleData.selectorInde
x())); | 65 attributeRules.append(RuleFeature(ruleData.rule(), ruleData.selectorInde
x())); |
| 264 } | 66 } |
| 265 | 67 |
| 266 DescendantInvalidationSet& RuleFeatureSet::ensureClassInvalidationSet(const Atom
icString& className) | 68 void RuleFeatureSet::collectFeaturesFromSelector(const CSSSelector& selector) |
| 267 { | 69 { |
| 268 InvalidationSetMap::AddResult addResult = m_classInvalidationSets.add(classN
ame, nullptr); | 70 addSelectorFeatures(selector); |
| 269 if (addResult.isNewEntry) | 71 |
| 270 addResult.storedValue->value = DescendantInvalidationSet::create(); | 72 for (const CSSSelector* current = &selector; current; current = current->tag
History()) |
| 271 return *addResult.storedValue->value; | 73 collectFeaturesFromSelectorList(current->selectorList()); |
| 272 } | 74 } |
| 273 | 75 |
| 274 DescendantInvalidationSet& RuleFeatureSet::ensureAttributeInvalidationSet(const
AtomicString& attributeName) | 76 void RuleFeatureSet::collectFeaturesFromSelectorList(const CSSSelectorList* sele
ctorList) |
| 275 { | |
| 276 InvalidationSetMap::AddResult addResult = m_attributeInvalidationSets.add(at
tributeName, nullptr); | |
| 277 if (addResult.isNewEntry) | |
| 278 addResult.storedValue->value = DescendantInvalidationSet::create(); | |
| 279 return *addResult.storedValue->value; | |
| 280 } | |
| 281 | |
| 282 DescendantInvalidationSet& RuleFeatureSet::ensureIdInvalidationSet(const AtomicS
tring& id) | |
| 283 { | |
| 284 InvalidationSetMap::AddResult addResult = m_idInvalidationSets.add(id, nullp
tr); | |
| 285 if (addResult.isNewEntry) | |
| 286 addResult.storedValue->value = DescendantInvalidationSet::create(); | |
| 287 return *addResult.storedValue->value; | |
| 288 } | |
| 289 | |
| 290 DescendantInvalidationSet& RuleFeatureSet::ensurePseudoInvalidationSet(CSSSelect
or::PseudoType pseudoType) | |
| 291 { | |
| 292 PseudoTypeInvalidationSetMap::AddResult addResult = m_pseudoInvalidationSets
.add(pseudoType, nullptr); | |
| 293 if (addResult.isNewEntry) | |
| 294 addResult.storedValue->value = DescendantInvalidationSet::create(); | |
| 295 return *addResult.storedValue->value; | |
| 296 } | |
| 297 | |
| 298 void RuleFeatureSet::collectFeaturesFromSelector(const CSSSelector& selector) | |
| 299 { | |
| 300 collectFeaturesFromSelector(selector, UseSubtreeStyleChange); | |
| 301 } | |
| 302 | |
| 303 void RuleFeatureSet::collectFeaturesFromSelector(const CSSSelector& selector, In
validationSetMode mode) | |
| 304 { | |
| 305 for (const CSSSelector* current = &selector; current; current = current->tag
History()) { | |
| 306 if (mode != AddFeatures) { | |
| 307 if (DescendantInvalidationSet* invalidationSet = invalidationSetForS
elector(*current)) { | |
| 308 if (mode == UseSubtreeStyleChange) | |
| 309 invalidationSet->setWholeSubtreeInvalid(); | |
| 310 } | |
| 311 } | |
| 312 | |
| 313 collectFeaturesFromSelectorList(current->selectorList(), mode); | |
| 314 } | |
| 315 } | |
| 316 | |
| 317 void RuleFeatureSet::collectFeaturesFromSelectorList(const CSSSelectorList* sele
ctorList, InvalidationSetMode mode) | |
| 318 { | 77 { |
| 319 if (!selectorList) | 78 if (!selectorList) |
| 320 return; | 79 return; |
| 321 | 80 |
| 322 for (const CSSSelector* selector = selectorList->first(); selector; selector
= CSSSelectorList::next(*selector)) | 81 for (const CSSSelector* selector = selectorList->first(); selector; selector
= CSSSelectorList::next(*selector)) |
| 323 collectFeaturesFromSelector(*selector, mode); | 82 collectFeaturesFromSelector(*selector); |
| 324 } | 83 } |
| 325 | 84 |
| 326 void RuleFeatureSet::add(const RuleFeatureSet& other) | 85 void RuleFeatureSet::add(const RuleFeatureSet& other) |
| 327 { | 86 { |
| 328 for (InvalidationSetMap::const_iterator it = other.m_classInvalidationSets.b
egin(); it != other.m_classInvalidationSets.end(); ++it) | 87 for (HashSet<AtomicString>::const_iterator it = other.m_classNames.begin();
it != other.m_classNames.end(); ++it) |
| 329 ensureClassInvalidationSet(it->key).combine(*it->value); | 88 m_classNames.add(*it); |
| 330 for (InvalidationSetMap::const_iterator it = other.m_attributeInvalidationSe
ts.begin(); it != other.m_attributeInvalidationSets.end(); ++it) | 89 for (HashSet<AtomicString>::const_iterator it = other.m_attributeNames.begin
(); it != other.m_attributeNames.end(); ++it) |
| 331 ensureAttributeInvalidationSet(it->key).combine(*it->value); | 90 m_attributeNames.add(*it); |
| 332 for (InvalidationSetMap::const_iterator it = other.m_idInvalidationSets.begi
n(); it != other.m_idInvalidationSets.end(); ++it) | 91 for (HashSet<AtomicString>::const_iterator it = other.m_idNames.begin(); it
!= other.m_idNames.end(); ++it) |
| 333 ensureIdInvalidationSet(it->key).combine(*it->value); | 92 m_idNames.add(*it); |
| 334 for (PseudoTypeInvalidationSetMap::const_iterator it = other.m_pseudoInvalid
ationSets.begin(); it != other.m_pseudoInvalidationSets.end(); ++it) | |
| 335 ensurePseudoInvalidationSet(static_cast<CSSSelector::PseudoType>(it->key
)).combine(*it->value); | |
| 336 | 93 |
| 337 attributeRules.appendVector(other.attributeRules); | 94 attributeRules.appendVector(other.attributeRules); |
| 338 } | 95 } |
| 339 | 96 |
| 340 void RuleFeatureSet::clear() | 97 void RuleFeatureSet::clear() |
| 341 { | 98 { |
| 342 attributeRules.clear(); | 99 attributeRules.clear(); |
| 343 m_classInvalidationSets.clear(); | 100 m_classNames.clear(); |
| 344 m_attributeInvalidationSets.clear(); | 101 m_attributeNames.clear(); |
| 345 m_idInvalidationSets.clear(); | 102 m_idNames.clear(); |
| 346 // We cannot clear m_styleInvalidator here, because the style invalidator mi
ght not | |
| 347 // have been evaluated yet. If not yet, in StyleInvalidator, there exists so
me element | |
| 348 // who has needsStyleInvlidation but does not have any invalidation list. | |
| 349 // This makes Blink not to recalc style correctly. crbug.com/344729. | |
| 350 } | 103 } |
| 351 | 104 |
| 352 void RuleFeatureSet::scheduleStyleInvalidationForClassChange(const SpaceSplitStr
ing& changedClasses, Element& element) | 105 void RuleFeatureSet::scheduleStyleInvalidationForClassChange(const SpaceSplitStr
ing& changedClasses, Element& element) |
| 353 { | 106 { |
| 354 unsigned changedSize = changedClasses.size(); | 107 unsigned changedSize = changedClasses.size(); |
| 355 for (unsigned i = 0; i < changedSize; ++i) { | 108 for (unsigned i = 0; i < changedSize; ++i) { |
| 356 addClassToInvalidationSet(changedClasses[i], element); | 109 scheduleStyleInvalidationForClassChange(changedClasses[i], element); |
| 357 } | 110 } |
| 358 } | 111 } |
| 359 | 112 |
| 360 void RuleFeatureSet::scheduleStyleInvalidationForClassChange(const SpaceSplitStr
ing& oldClasses, const SpaceSplitString& newClasses, Element& element) | 113 void RuleFeatureSet::scheduleStyleInvalidationForClassChange(const SpaceSplitStr
ing& oldClasses, const SpaceSplitString& newClasses, Element& element) |
| 361 { | 114 { |
| 362 if (!oldClasses.size()) { | 115 if (!oldClasses.size()) { |
| 363 scheduleStyleInvalidationForClassChange(newClasses, element); | 116 scheduleStyleInvalidationForClassChange(newClasses, element); |
| 364 return; | 117 return; |
| 365 } | 118 } |
| 366 | 119 |
| 367 // Class vectors tend to be very short. This is faster than using a hash tab
le. | 120 // Class vectors tend to be very short. This is faster than using a hash tab
le. |
| 368 BitVector remainingClassBits; | 121 BitVector remainingClassBits; |
| 369 remainingClassBits.ensureSize(oldClasses.size()); | 122 remainingClassBits.ensureSize(oldClasses.size()); |
| 370 | 123 |
| 371 for (unsigned i = 0; i < newClasses.size(); ++i) { | 124 for (unsigned i = 0; i < newClasses.size(); ++i) { |
| 372 bool found = false; | 125 bool found = false; |
| 373 for (unsigned j = 0; j < oldClasses.size(); ++j) { | 126 for (unsigned j = 0; j < oldClasses.size(); ++j) { |
| 374 if (newClasses[i] == oldClasses[j]) { | 127 if (newClasses[i] == oldClasses[j]) { |
| 375 // Mark each class that is still in the newClasses so we can ski
p doing | 128 // Mark each class that is still in the newClasses so we can ski
p doing |
| 376 // an n^2 search below when looking for removals. We can't break
from | 129 // an n^2 search below when looking for removals. We can't break
from |
| 377 // this loop early since a class can appear more than once. | 130 // this loop early since a class can appear more than once. |
| 378 remainingClassBits.quickSet(j); | 131 remainingClassBits.quickSet(j); |
| 379 found = true; | 132 found = true; |
| 380 } | 133 } |
| 381 } | 134 } |
| 382 // Class was added. | 135 // Class was added. |
| 383 if (!found) | 136 if (!found) |
| 384 addClassToInvalidationSet(newClasses[i], element); | 137 scheduleStyleInvalidationForClassChange(newClasses[i], element); |
| 385 } | 138 } |
| 386 | 139 |
| 387 for (unsigned i = 0; i < oldClasses.size(); ++i) { | 140 for (unsigned i = 0; i < oldClasses.size(); ++i) { |
| 388 if (remainingClassBits.quickGet(i)) | 141 if (remainingClassBits.quickGet(i)) |
| 389 continue; | 142 continue; |
| 390 // Class was removed. | 143 // Class was removed. |
| 391 addClassToInvalidationSet(oldClasses[i], element); | 144 scheduleStyleInvalidationForClassChange(oldClasses[i], element); |
| 392 } | 145 } |
| 393 } | 146 } |
| 394 | 147 |
| 395 void RuleFeatureSet::scheduleStyleInvalidationForAttributeChange(const Qualified
Name& attributeName, Element& element) | 148 void RuleFeatureSet::scheduleStyleInvalidationForAttributeChange(const Qualified
Name& attributeName, Element& element) |
| 396 { | 149 { |
| 397 | 150 if (m_attributeNames.contains(attributeName.localName())) |
| 398 if (RefPtr<DescendantInvalidationSet> invalidationSet = m_attributeInvalidat
ionSets.get(attributeName.localName())) | 151 element.setNeedsStyleRecalc(LocalStyleChange); |
| 399 m_styleInvalidator.scheduleInvalidation(invalidationSet, element); | |
| 400 } | 152 } |
| 401 | 153 |
| 402 void RuleFeatureSet::scheduleStyleInvalidationForIdChange(const AtomicString& ol
dId, const AtomicString& newId, Element& element) | 154 void RuleFeatureSet::scheduleStyleInvalidationForIdChange(const AtomicString& ol
dId, const AtomicString& newId, Element& element) |
| 403 { | 155 { |
| 404 if (!oldId.isEmpty()) { | 156 if (!oldId.isEmpty()) { |
| 405 if (RefPtr<DescendantInvalidationSet> invalidationSet = m_idInvalidation
Sets.get(oldId)) | 157 if (m_idNames.contains(oldId)) |
| 406 m_styleInvalidator.scheduleInvalidation(invalidationSet, element); | 158 element.setNeedsStyleRecalc(LocalStyleChange); |
| 407 } | 159 } |
| 408 if (!newId.isEmpty()) { | 160 if (!newId.isEmpty()) { |
| 409 if (RefPtr<DescendantInvalidationSet> invalidationSet = m_idInvalidation
Sets.get(newId)) | 161 if (m_idNames.contains(newId)) |
| 410 m_styleInvalidator.scheduleInvalidation(invalidationSet, element); | 162 element.setNeedsStyleRecalc(LocalStyleChange); |
| 411 } | 163 } |
| 412 } | 164 } |
| 413 | 165 |
| 414 void RuleFeatureSet::scheduleStyleInvalidationForPseudoChange(CSSSelector::Pseud
oType pseudo, Element& element) | 166 void RuleFeatureSet::scheduleStyleInvalidationForClassChange(const AtomicString&
className, Element& element) |
| 415 { | 167 { |
| 416 if (RefPtr<DescendantInvalidationSet> invalidationSet = m_pseudoInvalidation
Sets.get(pseudo)) | 168 if (m_classNames.contains(className)) |
| 417 m_styleInvalidator.scheduleInvalidation(invalidationSet, element); | 169 element.setNeedsStyleRecalc(LocalStyleChange); |
| 418 } | |
| 419 | |
| 420 void RuleFeatureSet::addClassToInvalidationSet(const AtomicString& className, El
ement& element) | |
| 421 { | |
| 422 if (RefPtr<DescendantInvalidationSet> invalidationSet = m_classInvalidationS
ets.get(className)) | |
| 423 m_styleInvalidator.scheduleInvalidation(invalidationSet, element); | |
| 424 } | |
| 425 | |
| 426 StyleInvalidator& RuleFeatureSet::styleInvalidator() | |
| 427 { | |
| 428 return m_styleInvalidator; | |
| 429 } | |
| 430 | |
| 431 void RuleFeatureSet::trace(Visitor* visitor) | |
| 432 { | |
| 433 #if ENABLE(OILPAN) | |
| 434 visitor->trace(attributeRules); | |
| 435 visitor->trace(m_classInvalidationSets); | |
| 436 visitor->trace(m_attributeInvalidationSets); | |
| 437 visitor->trace(m_idInvalidationSets); | |
| 438 visitor->trace(m_pseudoInvalidationSets); | |
| 439 visitor->trace(m_styleInvalidator); | |
| 440 #endif | |
| 441 } | 170 } |
| 442 | 171 |
| 443 } // namespace blink | 172 } // namespace blink |
| OLD | NEW |