Chromium Code Reviews| 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 29 matching lines...) Expand all Loading... | |
| 40 #include "core/css/invalidation/InvalidationSet.h" | 40 #include "core/css/invalidation/InvalidationSet.h" |
| 41 #include "core/dom/Element.h" | 41 #include "core/dom/Element.h" |
| 42 #include "core/dom/Node.h" | 42 #include "core/dom/Node.h" |
| 43 #include "core/inspector/InspectorTraceEvents.h" | 43 #include "core/inspector/InspectorTraceEvents.h" |
| 44 #include "wtf/BitVector.h" | 44 #include "wtf/BitVector.h" |
| 45 | 45 |
| 46 namespace blink { | 46 namespace blink { |
| 47 | 47 |
| 48 namespace { | 48 namespace { |
| 49 | 49 |
| 50 #if ENABLE(ASSERT) | |
| 51 | |
| 52 bool supportsInvalidation(CSSSelector::MatchType match) | 50 bool supportsInvalidation(CSSSelector::MatchType match) |
| 53 { | 51 { |
| 54 switch (match) { | 52 switch (match) { |
| 55 case CSSSelector::Tag: | 53 case CSSSelector::Tag: |
| 56 case CSSSelector::Id: | 54 case CSSSelector::Id: |
| 57 case CSSSelector::Class: | 55 case CSSSelector::Class: |
| 58 case CSSSelector::AttributeExact: | 56 case CSSSelector::AttributeExact: |
| 59 case CSSSelector::AttributeSet: | 57 case CSSSelector::AttributeSet: |
| 60 case CSSSelector::AttributeHyphen: | 58 case CSSSelector::AttributeHyphen: |
| 61 case CSSSelector::AttributeList: | 59 case CSSSelector::AttributeList: |
| 62 case CSSSelector::AttributeContain: | 60 case CSSSelector::AttributeContain: |
| 63 case CSSSelector::AttributeBegin: | 61 case CSSSelector::AttributeBegin: |
| 64 case CSSSelector::AttributeEnd: | 62 case CSSSelector::AttributeEnd: |
| 65 return true; | 63 return true; |
| 66 case CSSSelector::Unknown: | 64 case CSSSelector::Unknown: |
| 67 case CSSSelector::PagePseudoClass: | 65 case CSSSelector::PagePseudoClass: |
| 68 // These should not appear in StyleRule selectors. | 66 // These should not appear in StyleRule selectors. |
| 69 ASSERT_NOT_REACHED(); | 67 NOTREACHED(); |
| 70 return false; | 68 return false; |
| 71 default: | 69 default: |
| 72 // New match type added. Figure out if it needs a subtree invalidation o r not. | 70 // New match type added. Figure out if it needs a subtree invalidation o r not. |
| 73 ASSERT_NOT_REACHED(); | 71 NOTREACHED(); |
| 74 return false; | 72 return false; |
| 75 } | 73 } |
| 76 } | 74 } |
| 77 | 75 |
| 78 bool supportsInvalidation(CSSSelector::PseudoType type) | 76 bool supportsInvalidation(CSSSelector::PseudoType type) |
| 79 { | 77 { |
| 80 switch (type) { | 78 switch (type) { |
| 81 case CSSSelector::PseudoEmpty: | 79 case CSSSelector::PseudoEmpty: |
| 82 case CSSSelector::PseudoFirstChild: | 80 case CSSSelector::PseudoFirstChild: |
| 83 case CSSSelector::PseudoFirstOfType: | 81 case CSSSelector::PseudoFirstOfType: |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 155 case CSSSelector::PseudoSpatialNavigationFocus: | 153 case CSSSelector::PseudoSpatialNavigationFocus: |
| 156 case CSSSelector::PseudoListBox: | 154 case CSSSelector::PseudoListBox: |
| 157 case CSSSelector::PseudoHostHasAppearance: | 155 case CSSSelector::PseudoHostHasAppearance: |
| 158 case CSSSelector::PseudoSlotted: | 156 case CSSSelector::PseudoSlotted: |
| 159 return true; | 157 return true; |
| 160 case CSSSelector::PseudoUnknown: | 158 case CSSSelector::PseudoUnknown: |
| 161 case CSSSelector::PseudoLeftPage: | 159 case CSSSelector::PseudoLeftPage: |
| 162 case CSSSelector::PseudoRightPage: | 160 case CSSSelector::PseudoRightPage: |
| 163 case CSSSelector::PseudoFirstPage: | 161 case CSSSelector::PseudoFirstPage: |
| 164 // These should not appear in StyleRule selectors. | 162 // These should not appear in StyleRule selectors. |
| 165 ASSERT_NOT_REACHED(); | 163 NOTREACHED(); |
| 166 return false; | 164 return false; |
| 167 default: | 165 default: |
| 168 // New pseudo type added. Figure out if it needs a subtree invalidation or not. | 166 // New pseudo type added. Figure out if it needs a subtree invalidation or not. |
| 169 ASSERT_NOT_REACHED(); | 167 NOTREACHED(); |
| 170 return false; | 168 return false; |
| 171 } | 169 } |
| 172 } | 170 } |
| 173 | 171 |
| 174 bool supportsInvalidationWithSelectorList(CSSSelector::PseudoType pseudo) | 172 bool supportsInvalidationWithSelectorList(CSSSelector::PseudoType pseudo) |
| 175 { | 173 { |
| 176 return pseudo == CSSSelector::PseudoAny | 174 return pseudo == CSSSelector::PseudoAny |
| 177 || pseudo == CSSSelector::PseudoCue | 175 || pseudo == CSSSelector::PseudoCue |
| 178 || pseudo == CSSSelector::PseudoHost | 176 || pseudo == CSSSelector::PseudoHost |
| 179 || pseudo == CSSSelector::PseudoHostContext | 177 || pseudo == CSSSelector::PseudoHostContext |
| 180 || pseudo == CSSSelector::PseudoNot | 178 || pseudo == CSSSelector::PseudoNot |
| 181 || pseudo == CSSSelector::PseudoSlotted; | 179 || pseudo == CSSSelector::PseudoSlotted; |
| 182 } | 180 } |
| 183 | 181 |
| 184 #endif // ENABLE(ASSERT) | |
| 185 | |
| 186 bool requiresSubtreeInvalidation(const CSSSelector& selector) | 182 bool requiresSubtreeInvalidation(const CSSSelector& selector) |
| 187 { | 183 { |
| 188 if (selector.match() != CSSSelector::PseudoElement && selector.match() != CS SSelector::PseudoClass) { | 184 if (selector.match() != CSSSelector::PseudoElement && selector.match() != CS SSelector::PseudoClass) { |
| 189 ASSERT(supportsInvalidation(selector.match())); | 185 DCHECK(supportsInvalidation(selector.match())); |
| 190 return false; | 186 return false; |
| 191 } | 187 } |
| 192 | 188 |
| 193 switch (selector.getPseudoType()) { | 189 switch (selector.getPseudoType()) { |
| 194 case CSSSelector::PseudoFirstLine: | 190 case CSSSelector::PseudoFirstLine: |
| 195 case CSSSelector::PseudoFirstLetter: | 191 case CSSSelector::PseudoFirstLetter: |
| 196 // FIXME: Most pseudo classes/elements above can be supported and moved | 192 // FIXME: Most pseudo classes/elements above can be supported and moved |
| 197 // to assertSupportedPseudo(). Move on a case-by-case basis. If they | 193 // to assertSupportedPseudo(). Move on a case-by-case basis. If they |
| 198 // require subtree invalidation, document why. | 194 // require subtree invalidation, document why. |
| 199 case CSSSelector::PseudoHostContext: | 195 case CSSSelector::PseudoHostContext: |
| 200 // :host-context matches a shadow host, yet the simple selectors inside | 196 // :host-context matches a shadow host, yet the simple selectors inside |
| 201 // :host-context matches an ancestor of the shadow host. | 197 // :host-context matches an ancestor of the shadow host. |
| 202 return true; | 198 return true; |
| 203 default: | 199 default: |
| 204 ASSERT(supportsInvalidation(selector.getPseudoType())); | 200 DCHECK(supportsInvalidation(selector.getPseudoType())); |
| 205 return false; | 201 return false; |
| 206 } | 202 } |
| 207 } | 203 } |
| 208 | 204 |
| 209 template<class Map> | 205 template<class Map> |
| 210 InvalidationSet& ensureInvalidationSet(Map& map, const typename Map::KeyType& ke y, InvalidationType type) | 206 InvalidationSet& ensureInvalidationSet(Map& map, const typename Map::KeyType& ke y, InvalidationType type) |
| 211 { | 207 { |
| 212 typename Map::AddResult addResult = map.add(key, nullptr); | 208 typename Map::AddResult addResult = map.add(key, nullptr); |
| 213 if (addResult.isNewEntry) { | 209 if (addResult.isNewEntry) { |
| 214 if (type == InvalidateDescendants) | 210 if (type == InvalidateDescendants) |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 287 ALWAYS_INLINE InvalidationSet& RuleFeatureSet::ensureIdInvalidationSet(const Ato micString& id, InvalidationType type) | 283 ALWAYS_INLINE InvalidationSet& RuleFeatureSet::ensureIdInvalidationSet(const Ato micString& id, InvalidationType type) |
| 288 { | 284 { |
| 289 return ensureInvalidationSet(m_idInvalidationSets, id, type); | 285 return ensureInvalidationSet(m_idInvalidationSets, id, type); |
| 290 } | 286 } |
| 291 | 287 |
| 292 ALWAYS_INLINE InvalidationSet& RuleFeatureSet::ensurePseudoInvalidationSet(CSSSe lector::PseudoType pseudoType, InvalidationType type) | 288 ALWAYS_INLINE InvalidationSet& RuleFeatureSet::ensurePseudoInvalidationSet(CSSSe lector::PseudoType pseudoType, InvalidationType type) |
| 293 { | 289 { |
| 294 return ensureInvalidationSet(m_pseudoInvalidationSets, pseudoType, type); | 290 return ensureInvalidationSet(m_pseudoInvalidationSets, pseudoType, type); |
| 295 } | 291 } |
| 296 | 292 |
| 297 bool RuleFeatureSet::extractInvalidationSetFeature(const CSSSelector& selector, InvalidationSetFeatures& features) | 293 void RuleFeatureSet::updateFeaturesFromCombinator( |
| 294 const CSSSelector& lastInCompound, | |
| 295 const CSSSelector* lastCompoundInAdjacentChain, | |
| 296 InvalidationSetFeatures& lastCompoundInAdjacentChainFeatures, | |
| 297 InvalidationSetFeatures*& siblingFeatures, | |
| 298 InvalidationSetFeatures& descendantFeatures) | |
| 299 { | |
| 300 if (lastInCompound.isAdjacentSelector()) { | |
| 301 if (!siblingFeatures) { | |
| 302 siblingFeatures = &lastCompoundInAdjacentChainFeatures; | |
| 303 if (lastCompoundInAdjacentChain) { | |
| 304 extractInvalidationSetFeaturesFromCompound(*lastCompoundInAdjace ntChain, lastCompoundInAdjacentChainFeatures, Ancestor); | |
| 305 if (!lastCompoundInAdjacentChainFeatures.hasFeatures()) | |
| 306 lastCompoundInAdjacentChainFeatures.forceSubtree = true; | |
| 307 } | |
| 308 } | |
| 309 if (siblingFeatures->maxDirectAdjacentSelectors == UINT_MAX) | |
| 310 return; | |
| 311 if (lastInCompound.relation() == CSSSelector::DirectAdjacent) | |
| 312 ++siblingFeatures->maxDirectAdjacentSelectors; | |
| 313 else | |
| 314 siblingFeatures->maxDirectAdjacentSelectors = UINT_MAX; | |
| 315 return; | |
| 316 } | |
| 317 | |
| 318 if (siblingFeatures && lastCompoundInAdjacentChainFeatures.maxDirectAdjacent Selectors) | |
| 319 lastCompoundInAdjacentChainFeatures = InvalidationSetFeatures(); | |
| 320 | |
| 321 siblingFeatures = nullptr; | |
| 322 | |
| 323 if (lastInCompound.isShadowSelector()) | |
| 324 descendantFeatures.treeBoundaryCrossing = true; | |
| 325 if (lastInCompound.relation() == CSSSelector::ShadowSlot || lastInCompound.r elationIsAffectedByPseudoContent()) | |
| 326 descendantFeatures.insertionPointCrossing = true; | |
| 327 if (lastInCompound.relationIsAffectedByPseudoContent()) | |
| 328 descendantFeatures.contentPseudoCrossing = true; | |
| 329 } | |
| 330 | |
| 331 void RuleFeatureSet::extractInvalidationSetFeaturesFromSimpleSelector(const CSSS elector& selector, InvalidationSetFeatures& features) | |
| 298 { | 332 { |
| 299 if (selector.match() == CSSSelector::Tag && selector.tagQName().localName() != starAtom) { | 333 if (selector.match() == CSSSelector::Tag && selector.tagQName().localName() != starAtom) { |
| 300 features.tagNames.append(selector.tagQName().localName()); | 334 features.tagNames.append(selector.tagQName().localName()); |
| 301 return true; | 335 return; |
| 302 } | 336 } |
| 303 if (selector.match() == CSSSelector::Id) { | 337 if (selector.match() == CSSSelector::Id) { |
| 304 features.ids.append(selector.value()); | 338 features.ids.append(selector.value()); |
| 305 return true; | 339 return; |
| 306 } | 340 } |
| 307 if (selector.match() == CSSSelector::Class) { | 341 if (selector.match() == CSSSelector::Class) { |
| 308 features.classes.append(selector.value()); | 342 features.classes.append(selector.value()); |
| 309 return true; | 343 return; |
| 310 } | 344 } |
| 311 if (selector.isAttributeSelector()) { | 345 if (selector.isAttributeSelector()) { |
| 312 features.attributes.append(selector.attribute().localName()); | 346 features.attributes.append(selector.attribute().localName()); |
| 313 return true; | 347 return; |
| 314 } | 348 } |
| 315 if (selector.getPseudoType() == CSSSelector::PseudoWebKitCustomElement || se lector.getPseudoType() == CSSSelector::PseudoBlinkInternalElement) { | 349 switch (selector.getPseudoType()) { |
| 350 case CSSSelector::PseudoWebKitCustomElement: | |
| 351 case CSSSelector::PseudoBlinkInternalElement: | |
| 316 features.customPseudoElement = true; | 352 features.customPseudoElement = true; |
| 317 return true; | 353 return; |
| 354 case CSSSelector::PseudoBefore: | |
| 355 case CSSSelector::PseudoAfter: | |
| 356 features.hasBeforeOrAfter = true; | |
| 357 return; | |
| 358 case CSSSelector::PseudoSlotted: | |
| 359 features.invalidatesSlotted = true; | |
| 360 return; | |
| 361 default: | |
| 362 return; | |
| 318 } | 363 } |
| 319 // Returning false for ::before and ::after as they are not used as | |
| 320 // invalidation set features, only used later to generate invalidation sets | |
| 321 // for attributes present in "content: attr(...)" declarations. | |
| 322 if (selector.getPseudoType() == CSSSelector::PseudoBefore || selector.getPse udoType() == CSSSelector::PseudoAfter) | |
| 323 features.hasBeforeOrAfter = true; | |
| 324 return false; | |
| 325 } | 364 } |
| 326 | 365 |
| 327 InvalidationSet* RuleFeatureSet::invalidationSetForSelector(const CSSSelector& s elector, InvalidationType type) | 366 InvalidationSet* RuleFeatureSet::invalidationSetForSimpleSelector(const CSSSelec tor& selector, InvalidationType type) |
| 328 { | 367 { |
| 329 if (selector.match() == CSSSelector::Class) | 368 if (selector.match() == CSSSelector::Class) |
| 330 return &ensureClassInvalidationSet(selector.value(), type); | 369 return &ensureClassInvalidationSet(selector.value(), type); |
| 331 if (selector.isAttributeSelector()) | 370 if (selector.isAttributeSelector()) |
| 332 return &ensureAttributeInvalidationSet(selector.attribute().localName(), type); | 371 return &ensureAttributeInvalidationSet(selector.attribute().localName(), type); |
| 333 if (selector.match() == CSSSelector::Id) | 372 if (selector.match() == CSSSelector::Id) |
| 334 return &ensureIdInvalidationSet(selector.value(), type); | 373 return &ensureIdInvalidationSet(selector.value(), type); |
| 335 if (selector.match() == CSSSelector::PseudoClass) { | 374 if (selector.match() == CSSSelector::PseudoClass) { |
| 336 switch (selector.getPseudoType()) { | 375 switch (selector.getPseudoType()) { |
| 337 case CSSSelector::PseudoEmpty: | 376 case CSSSelector::PseudoEmpty: |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 375 case CSSSelector::PseudoNthLastChild: | 414 case CSSSelector::PseudoNthLastChild: |
| 376 case CSSSelector::PseudoNthLastOfType: | 415 case CSSSelector::PseudoNthLastOfType: |
| 377 return &ensureNthInvalidationSet(); | 416 return &ensureNthInvalidationSet(); |
| 378 default: | 417 default: |
| 379 break; | 418 break; |
| 380 } | 419 } |
| 381 } | 420 } |
| 382 return nullptr; | 421 return nullptr; |
| 383 } | 422 } |
| 384 | 423 |
| 385 // Given a rule, update the descendant invalidation sets for the features found | |
| 386 // in its selector. The first step is to extract the features from the rightmost | |
| 387 // compound selector (extractInvalidationSetFeatures). Secondly, add those featu res | |
| 388 // to the invalidation sets for the features found in the other compound selecto rs | |
| 389 // (addFeaturesToInvalidationSets). If we find a feature in the right-most compo und | |
| 390 // selector that requires a subtree recalc, we addFeaturesToInvalidationSets for the | |
| 391 // rightmost compound selector as well. | |
| 392 | |
| 393 void RuleFeatureSet::updateInvalidationSets(const RuleData& ruleData) | 424 void RuleFeatureSet::updateInvalidationSets(const RuleData& ruleData) |
| 394 { | 425 { |
| 426 // Given a rule, update the descendant invalidation sets for the features | |
| 427 // found in its selector. The first step is to extract the features from the | |
| 428 // rightmost compound selector (extractInvalidationSetFeatures). Secondly, | |
|
Eric Willigers
2016/09/03 02:57:57
extractInvalidationSetFeatures becomes
extractInva
rune
2016/09/05 08:16:20
Done.
| |
| 429 // add those features to the invalidation sets for the features found in the | |
| 430 // other compound selectors (addFeaturesToInvalidationSets). If we find a | |
| 431 // feature in the right-most compound selector that requires a subtree | |
| 432 // recalc, nextCompound will be the rightmost compound and we will | |
| 433 // addFeaturesToInvalidationSets for that one as well. | |
| 434 | |
| 395 InvalidationSetFeatures features; | 435 InvalidationSetFeatures features; |
| 396 auto result = extractInvalidationSetFeatures(ruleData.selector(), features, Subject); | 436 const CSSSelector* nextCompound = extractInvalidationSetFeaturesFromCompound (ruleData.selector(), features, Subject); |
| 397 | 437 |
| 398 features.forceSubtree = result.second == ForceSubtree; | 438 if (!features.hasFeatures()) |
| 399 if (result.first) { | 439 features.forceSubtree = true; |
| 400 addFeaturesToInvalidationSets(result.first, features.adjacent ? &feature s : nullptr, features); | |
| 401 } else if (features.hasNthPseudo) { | |
| 402 DCHECK(m_nthInvalidationSet); | |
| 403 addFeaturesToInvalidationSet(*m_nthInvalidationSet, features); | |
| 404 } | |
| 405 | 440 |
| 406 // If any ::before and ::after rules specify 'content: attr(...)', we | 441 if (nextCompound) |
| 407 // need to create invalidation sets for those attributes. | 442 addFeaturesToInvalidationSets(*nextCompound, features); |
| 443 else if (features.hasNthPseudo) | |
| 444 addFeaturesToInvalidationSet(ensureNthInvalidationSet(), features); | |
| 445 | |
| 408 if (features.hasBeforeOrAfter) | 446 if (features.hasBeforeOrAfter) |
| 409 updateInvalidationSetsForContentAttribute(ruleData); | 447 updateInvalidationSetsForContentAttribute(ruleData); |
| 410 } | 448 } |
| 411 | 449 |
| 412 void RuleFeatureSet::updateInvalidationSetsForContentAttribute(const RuleData& r uleData) | 450 void RuleFeatureSet::updateInvalidationSetsForContentAttribute(const RuleData& r uleData) |
| 413 { | 451 { |
| 452 // If any ::before and ::after rules specify 'content: attr(...)', we | |
| 453 // need to create invalidation sets for those attributes to have content | |
| 454 // changes applied through style recalc. | |
| 455 | |
| 414 const StylePropertySet& propertySet = ruleData.rule()->properties(); | 456 const StylePropertySet& propertySet = ruleData.rule()->properties(); |
| 415 | 457 |
| 416 int propertyIndex = propertySet.findPropertyIndex(CSSPropertyContent); | 458 int propertyIndex = propertySet.findPropertyIndex(CSSPropertyContent); |
| 417 | 459 |
| 418 if (propertyIndex == -1) | 460 if (propertyIndex == -1) |
| 419 return; | 461 return; |
| 420 | 462 |
| 421 StylePropertySet::PropertyReference contentProperty = propertySet.propertyAt (propertyIndex); | 463 StylePropertySet::PropertyReference contentProperty = propertySet.propertyAt (propertyIndex); |
| 422 const CSSValue& contentValue = contentProperty.value(); | 464 const CSSValue& contentValue = contentProperty.value(); |
| 423 | 465 |
| 424 if (!contentValue.isValueList()) | 466 if (!contentValue.isValueList()) |
| 425 return; | 467 return; |
| 426 | 468 |
| 427 for (auto& item : toCSSValueList(contentValue)) { | 469 for (auto& item : toCSSValueList(contentValue)) { |
| 428 if (!item->isFunctionValue()) | 470 if (!item->isFunctionValue()) |
| 429 continue; | 471 continue; |
| 430 const CSSFunctionValue* functionValue = toCSSFunctionValue(item.get()); | 472 const CSSFunctionValue* functionValue = toCSSFunctionValue(item.get()); |
| 431 if (functionValue->functionType() != CSSValueAttr) | 473 if (functionValue->functionType() != CSSValueAttr) |
| 432 continue; | 474 continue; |
| 433 ensureAttributeInvalidationSet(AtomicString(toCSSCustomIdentValue(functi onValue->item(0)).value()), InvalidateDescendants).setInvalidatesSelf(); | 475 ensureAttributeInvalidationSet(AtomicString(toCSSCustomIdentValue(functi onValue->item(0)).value()), InvalidateDescendants).setInvalidatesSelf(); |
| 434 } | 476 } |
| 435 } | 477 } |
| 436 | 478 |
| 437 std::pair<const CSSSelector*, RuleFeatureSet::UseFeaturesType> | 479 const CSSSelector* |
| 438 RuleFeatureSet::extractInvalidationSetFeatures(const CSSSelector& selector, Inva lidationSetFeatures& features, PositionType position, CSSSelector::PseudoType ps eudo) | 480 RuleFeatureSet::extractInvalidationSetFeaturesFromSelectorList(const CSSSelector & simpleSelector, InvalidationSetFeatures& features, PositionType position) |
| 439 { | 481 { |
| 440 bool foundFeatures = false; | 482 const CSSSelectorList* selectorList = simpleSelector.selectorList(); |
| 441 for (const CSSSelector* current = &selector; current; current = current->tag History()) { | 483 if (!selectorList) |
| 442 if (pseudo != CSSSelector::PseudoNot) | 484 return nullptr; |
| 443 foundFeatures |= extractInvalidationSetFeature(*current, features); | 485 |
| 444 // Initialize the entry in the invalidation set map, if supported. | 486 DCHECK(supportsInvalidationWithSelectorList(simpleSelector.getPseudoType())) ; |
| 445 if (InvalidationSet* invalidationSet = invalidationSetForSelector(*curre nt, InvalidateDescendants)) { | 487 |
| 446 if (position == Subject) { | 488 const CSSSelector* subSelector = selectorList->first(); |
| 447 if (invalidationSet == m_nthInvalidationSet) | 489 |
| 448 features.hasNthPseudo = true; | 490 bool allSubSelectorsHaveFeatures = true; |
| 449 else | 491 InvalidationSetFeatures anyFeatures; |
| 450 invalidationSet->setInvalidatesSelf(); | 492 |
| 451 } | 493 for (; subSelector; subSelector = CSSSelectorList::next(*subSelector)) { |
| 452 } else { | 494 InvalidationSetFeatures compoundFeatures; |
| 453 if (requiresSubtreeInvalidation(*current)) { | 495 if (extractInvalidationSetFeaturesFromCompound(*subSelector, compoundFea tures, position, simpleSelector.getPseudoType())) { |
| 454 // Fall back to use subtree invalidations, even for features in the | 496 // A non-null selector return means the sub-selector contained a |
| 455 // rightmost compound selector. Returning the start &selector he re | 497 // selector which requiresSubtreeInvalidation(). |
| 456 // will make addFeaturesToInvalidationSets start marking invalid ation | 498 DCHECK(compoundFeatures.forceSubtree); |
| 457 // sets for subtree recalc for features in the rightmost compoun d | 499 features.forceSubtree = true; |
| 458 // selector. | 500 return &simpleSelector; |
| 459 return std::make_pair(&selector, ForceSubtree); | 501 } |
| 460 } | 502 if (allSubSelectorsHaveFeatures && !compoundFeatures.hasFeatures()) |
| 461 if (const CSSSelectorList* selectorList = current->selectorList()) { | 503 allSubSelectorsHaveFeatures = false; |
| 462 if (current->getPseudoType() == CSSSelector::PseudoSlotted) { | 504 else |
| 463 ASSERT(position == Subject); | 505 anyFeatures.add(compoundFeatures); |
| 464 features.invalidatesSlotted = true; | 506 if (compoundFeatures.hasNthPseudo) |
| 465 } | 507 features.hasNthPseudo = true; |
| 466 ASSERT(supportsInvalidationWithSelectorList(current->getPseudoTy pe())); | 508 } |
| 467 const CSSSelector* subSelector = selectorList->first(); | 509 // Don't add any features if one of the sub-selectors of does not contain |
| 468 bool allSubSelectorsHaveFeatures = !!subSelector; | 510 // any invalidation set features. E.g. :-webkit-any(*, span). |
| 469 for (; subSelector; subSelector = CSSSelectorList::next(*subSele ctor)) { | 511 if (allSubSelectorsHaveFeatures) |
| 470 auto result = extractInvalidationSetFeatures(*subSelector, f eatures, position, current->getPseudoType()); | 512 features.add(anyFeatures); |
| 471 if (result.first) { | 513 return nullptr; |
| 472 // A non-null selector return means the sub-selector con tained a | 514 } |
| 473 // selector which requiresSubtreeInvalidation(). Return the rightmost | 515 |
| 474 // selector to mark for subtree recalcs like above. | 516 const CSSSelector* |
| 475 return std::make_pair(&selector, ForceSubtree); | 517 RuleFeatureSet::extractInvalidationSetFeaturesFromCompound(const CSSSelector& co mpound, InvalidationSetFeatures& features, PositionType position, CSSSelector::P seudoType pseudo) |
| 476 } | 518 { |
| 477 allSubSelectorsHaveFeatures &= result.second == UseFeatures; | 519 const CSSSelector* simpleSelector = &compound; |
| 478 } | 520 for (; simpleSelector; simpleSelector = simpleSelector->tagHistory()) { |
| 479 foundFeatures |= allSubSelectorsHaveFeatures; | 521 |
| 480 } | 522 // Fall back to use subtree invalidations, even for features in the |
| 523 // rightmost compound selector. Returning the start &selector here | |
| 524 // will make addFeaturesToInvalidationSets start marking invalidation | |
| 525 // sets for subtree recalc for features in the rightmost compound | |
| 526 // selector. | |
| 527 if (requiresSubtreeInvalidation(*simpleSelector)) { | |
| 528 features.forceSubtree = true; | |
| 529 return &compound; | |
| 481 } | 530 } |
| 482 | 531 |
| 483 if (current->relation() == CSSSelector::SubSelector) | 532 // When inside a :not(), we should not use the found features for |
| 533 // invalidation because we should invalidate elements _without_ that | |
| 534 // feature. On the other hand, we should still have invalidation sets | |
| 535 // for the features since we are able to detect when they change. | |
| 536 // That is, ".a" should not have ".b" in its invalidation set for | |
| 537 // ".a :not(.b)", but there should be an invalidation set for ".a" in | |
| 538 // ":not(.a) .b". | |
| 539 if (pseudo != CSSSelector::PseudoNot) | |
| 540 extractInvalidationSetFeaturesFromSimpleSelector(*simpleSelector, fe atures); | |
| 541 | |
| 542 // Initialize the entry in the invalidation set map for self- | |
| 543 // invalidation, if supported. | |
| 544 if (InvalidationSet* invalidationSet = invalidationSetForSimpleSelector( *simpleSelector, InvalidateDescendants)) { | |
| 545 if (invalidationSet == m_nthInvalidationSet) | |
| 546 features.hasNthPseudo = true; | |
| 547 else if (position == Subject) | |
| 548 invalidationSet->setInvalidatesSelf(); | |
| 549 } | |
| 550 | |
| 551 if (extractInvalidationSetFeaturesFromSelectorList(*simpleSelector, feat ures, position)) { | |
| 552 DCHECK(features.forceSubtree); | |
| 553 return &compound; | |
| 554 } | |
| 555 | |
| 556 if (simpleSelector->relation() == CSSSelector::SubSelector) | |
| 484 continue; | 557 continue; |
| 485 | 558 |
| 486 if (features.hasNthPseudo && position == Subject) { | 559 if (position == Subject) { |
| 487 DCHECK(m_nthInvalidationSet); | 560 if (features.hasNthPseudo) { |
| 488 if (foundFeatures) | 561 DCHECK(m_nthInvalidationSet); |
| 489 addFeaturesToInvalidationSet(*m_nthInvalidationSet, features); | 562 if (features.hasFeatures()) |
| 490 else | 563 addFeaturesToInvalidationSet(*m_nthInvalidationSet, features ); |
| 491 m_nthInvalidationSet->setWholeSubtreeInvalid(); | 564 else |
| 565 m_nthInvalidationSet->setWholeSubtreeInvalid(); | |
| 566 } | |
| 567 InvalidationSetFeatures* siblingFeatures = nullptr; | |
| 568 updateFeaturesFromCombinator(*simpleSelector, nullptr, features, sib lingFeatures, features); | |
| 492 } | 569 } |
| 570 return simpleSelector->tagHistory(); | |
| 571 } | |
| 493 | 572 |
| 494 features.treeBoundaryCrossing = current->isShadowSelector(); | 573 return nullptr; |
| 495 if (current->relationIsAffectedByPseudoContent()) { | |
| 496 features.contentPseudoCrossing = true; | |
| 497 features.insertionPointCrossing = true; | |
| 498 } | |
| 499 features.adjacent = current->isAdjacentSelector(); | |
| 500 if (current->relation() == CSSSelector::DirectAdjacent) | |
| 501 features.maxDirectAdjacentSelectors = 1; | |
| 502 return std::make_pair(current->tagHistory(), foundFeatures ? UseFeatures : ForceSubtree); | |
| 503 } | |
| 504 return std::make_pair(nullptr, foundFeatures ? UseFeatures : ForceSubtree); | |
| 505 } | 574 } |
| 506 | 575 |
| 507 // Add features extracted from the rightmost compound selector to descendant inv alidation | 576 // Add features extracted from the rightmost compound selector to descendant inv alidation |
| 508 // sets for features found in other compound selectors. | 577 // sets for features found in other compound selectors. |
| 509 // | 578 // |
| 510 // We use descendant invalidation for descendants, sibling invalidation for sibl ings and their subtrees. | 579 // We use descendant invalidation for descendants, sibling invalidation for sibl ings and their subtrees. |
| 511 // | 580 // |
| 512 // As we encounter a descendant type of combinator, the features only need to be checked | 581 // As we encounter a descendant type of combinator, the features only need to be checked |
| 513 // against descendants in the same subtree only. features.adjacent is set to fal se, and | 582 // against descendants in the same subtree only. features.adjacent is set to fal se, and |
| 514 // we start adding features to the descendant invalidation set. | 583 // we start adding features to the descendant invalidation set. |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 531 for (const auto& tagName : features.tagNames) | 600 for (const auto& tagName : features.tagNames) |
| 532 invalidationSet.addTagName(tagName); | 601 invalidationSet.addTagName(tagName); |
| 533 for (const auto& className : features.classes) | 602 for (const auto& className : features.classes) |
| 534 invalidationSet.addClass(className); | 603 invalidationSet.addClass(className); |
| 535 for (const auto& attribute : features.attributes) | 604 for (const auto& attribute : features.attributes) |
| 536 invalidationSet.addAttribute(attribute); | 605 invalidationSet.addAttribute(attribute); |
| 537 if (features.customPseudoElement) | 606 if (features.customPseudoElement) |
| 538 invalidationSet.setCustomPseudoInvalid(); | 607 invalidationSet.setCustomPseudoInvalid(); |
| 539 } | 608 } |
| 540 | 609 |
| 541 // selector is the selector immediately to the left of the rightmost combinator. | 610 |
| 542 // siblingFeatures is null if selector is not immediately to the left of a sibli ng combinator. | 611 void RuleFeatureSet::addFeaturesToInvalidationSetsForSelectorList(const CSSSelec tor& simpleSelector, InvalidationSetFeatures* siblingFeatures, InvalidationSetFe atures& descendantFeatures) |
| 543 // descendantFeatures has the features of the rightmost compound selector. | |
| 544 void RuleFeatureSet::addFeaturesToInvalidationSets(const CSSSelector* selector, InvalidationSetFeatures* siblingFeatures, InvalidationSetFeatures& descendantFea tures) | |
| 545 { | 612 { |
| 546 const CSSSelector* lastCompoundSelectorInAdjacentChain = selector; | 613 if (!simpleSelector.selectorList()) |
| 614 return; | |
| 547 | 615 |
| 548 // We set siblingFeatures to &localFeatures if we find a rightmost sibling c ombinator. | 616 DCHECK(supportsInvalidationWithSelectorList(simpleSelector.getPseudoType())) ; |
| 549 InvalidationSetFeatures localFeatures; | |
| 550 | 617 |
| 551 bool universalCompound = true; | 618 for (const CSSSelector* subSelector = simpleSelector.selectorList()->first() ; subSelector; subSelector = CSSSelectorList::next(*subSelector)) |
| 619 addFeaturesToInvalidationSetsForCompoundSelector(*subSelector, siblingFe atures, descendantFeatures); | |
| 620 } | |
| 552 | 621 |
| 553 for (const CSSSelector* current = selector; current; current = current->tagH istory()) { | 622 void RuleFeatureSet::addFeaturesToInvalidationSetsForSimpleSelector(const CSSSel ector& simpleSelector, InvalidationSetFeatures* siblingFeatures, InvalidationSet Features& descendantFeatures) |
| 554 InvalidationType type = siblingFeatures ? InvalidateSiblings : Invalidat eDescendants; | 623 { |
| 555 if (InvalidationSet* invalidationSet = invalidationSetForSelector(*curre nt, type)) { | 624 if (InvalidationSet* invalidationSet = invalidationSetForSimpleSelector(simp leSelector, siblingFeatures ? InvalidateSiblings : InvalidateDescendants)) { |
| 556 if (current->match() != CSSSelector::PseudoClass) | 625 if (!siblingFeatures || invalidationSet == m_nthInvalidationSet) { |
| 557 universalCompound = false; | 626 addFeaturesToInvalidationSet(*invalidationSet, descendantFeatures); |
| 558 if (siblingFeatures && invalidationSet != m_nthInvalidationSet) { | 627 return; |
| 559 SiblingInvalidationSet* siblingInvalidationSet = toSiblingInvali dationSet(invalidationSet); | |
| 560 siblingInvalidationSet->updateMaxDirectAdjacentSelectors(sibling Features->maxDirectAdjacentSelectors); | |
| 561 | |
| 562 addFeaturesToInvalidationSet(*invalidationSet, *siblingFeatures) ; | |
| 563 if (siblingFeatures == &descendantFeatures) | |
| 564 siblingInvalidationSet->setInvalidatesSelf(); | |
| 565 else | |
| 566 addFeaturesToInvalidationSet(siblingInvalidationSet->ensureS iblingDescendants(), descendantFeatures); | |
| 567 } else { | |
| 568 addFeaturesToInvalidationSet(*invalidationSet, descendantFeature s); | |
| 569 } | |
| 570 } else { | |
| 571 if (current->isHostPseudoClass()) | |
| 572 descendantFeatures.treeBoundaryCrossing = true; | |
| 573 if (current->isInsertionPointCrossing()) | |
| 574 descendantFeatures.insertionPointCrossing = true; | |
| 575 if (const CSSSelectorList* selectorList = current->selectorList()) { | |
| 576 ASSERT(supportsInvalidationWithSelectorList(current->getPseudoTy pe())); | |
| 577 for (const CSSSelector* subSelector = selectorList->first(); sub Selector; subSelector = CSSSelectorList::next(*subSelector)) | |
| 578 addFeaturesToInvalidationSets(subSelector, siblingFeatures, descendantFeatures); | |
| 579 } | |
| 580 } | 628 } |
| 581 | 629 |
| 582 if (current->relation() == CSSSelector::SubSelector) | 630 SiblingInvalidationSet* siblingInvalidationSet = toSiblingInvalidationSe t(invalidationSet); |
| 583 continue; | 631 siblingInvalidationSet->updateMaxDirectAdjacentSelectors(siblingFeatures ->maxDirectAdjacentSelectors); |
| 584 | 632 addFeaturesToInvalidationSet(*invalidationSet, *siblingFeatures); |
| 585 if (universalCompound && siblingFeatures) | 633 if (siblingFeatures == &descendantFeatures) |
| 586 addFeaturesToUniversalSiblingInvalidationSet(*siblingFeatures, desce ndantFeatures); | 634 siblingInvalidationSet->setInvalidatesSelf(); |
| 587 universalCompound = true; | 635 else |
| 588 | 636 addFeaturesToInvalidationSet(siblingInvalidationSet->ensureSiblingDe scendants(), descendantFeatures); |
| 589 if (current->relationIsAffectedByPseudoContent() || current->relation() == CSSSelector::ShadowSlot) { | 637 return; |
| 590 descendantFeatures.insertionPointCrossing = true; | |
| 591 descendantFeatures.contentPseudoCrossing = true; | |
| 592 } | |
| 593 if (current->isShadowSelector()) | |
| 594 descendantFeatures.treeBoundaryCrossing = true; | |
| 595 if (!current->isAdjacentSelector()) { | |
| 596 lastCompoundSelectorInAdjacentChain = current->tagHistory(); | |
| 597 siblingFeatures = nullptr; | |
| 598 continue; | |
| 599 } | |
| 600 | |
| 601 if (siblingFeatures) { | |
| 602 if (siblingFeatures->maxDirectAdjacentSelectors == UINT_MAX) | |
| 603 continue; | |
| 604 | |
| 605 if (current->relation() == CSSSelector::DirectAdjacent) | |
| 606 siblingFeatures->maxDirectAdjacentSelectors++; | |
| 607 else | |
| 608 siblingFeatures->maxDirectAdjacentSelectors = UINT_MAX; | |
| 609 continue; | |
| 610 } | |
| 611 | |
| 612 localFeatures = InvalidationSetFeatures(); | |
| 613 auto result = extractInvalidationSetFeatures(*lastCompoundSelectorInAdja centChain, localFeatures, Ancestor); | |
| 614 ASSERT(result.first); | |
| 615 localFeatures.forceSubtree = result.second == ForceSubtree; | |
| 616 siblingFeatures = &localFeatures; | |
| 617 } | 638 } |
| 618 | 639 |
| 619 if (universalCompound && siblingFeatures) | 640 if (simpleSelector.isHostPseudoClass()) |
| 641 descendantFeatures.treeBoundaryCrossing = true; | |
| 642 if (simpleSelector.isInsertionPointCrossing()) | |
| 643 descendantFeatures.insertionPointCrossing = true; | |
| 644 | |
| 645 addFeaturesToInvalidationSetsForSelectorList(simpleSelector, siblingFeatures , descendantFeatures); | |
| 646 } | |
| 647 | |
| 648 const CSSSelector* RuleFeatureSet::addFeaturesToInvalidationSetsForCompoundSelec tor(const CSSSelector& compound, InvalidationSetFeatures* siblingFeatures, Inval idationSetFeatures& descendantFeatures) | |
| 649 { | |
| 650 bool compoundHasTagIdClassOrAttribute = false; | |
| 651 const CSSSelector* simpleSelector = &compound; | |
| 652 for (; simpleSelector; simpleSelector = simpleSelector->tagHistory()) { | |
| 653 addFeaturesToInvalidationSetsForSimpleSelector(*simpleSelector, siblingF eatures, descendantFeatures); | |
| 654 if (siblingFeatures) | |
| 655 compoundHasTagIdClassOrAttribute |= simpleSelector->isIdClassOrAttri buteSelector(); | |
|
Eric Willigers
2016/09/03 02:57:57
tag? Should the CSSSelector method also consider t
rune
2016/09/05 08:16:20
Then we would need to have invalidation sets for t
| |
| 656 if (simpleSelector->relation() != CSSSelector::SubSelector) | |
| 657 break; | |
| 658 if (!simpleSelector->tagHistory()) | |
| 659 break; | |
| 660 } | |
| 661 | |
| 662 if (siblingFeatures && !compoundHasTagIdClassOrAttribute) | |
| 620 addFeaturesToUniversalSiblingInvalidationSet(*siblingFeatures, descendan tFeatures); | 663 addFeaturesToUniversalSiblingInvalidationSet(*siblingFeatures, descendan tFeatures); |
| 664 | |
| 665 return simpleSelector; | |
| 666 } | |
| 667 | |
| 668 void RuleFeatureSet::addFeaturesToInvalidationSets(const CSSSelector& selector, InvalidationSetFeatures& descendantFeatures) | |
| 669 { | |
| 670 // selector is the selector immediately to the left of the rightmost combina tor. | |
| 671 // descendantFeatures has the features of the rightmost compound selector. | |
| 672 | |
| 673 InvalidationSetFeatures lastCompoundInSiblingChainFeatures; | |
| 674 InvalidationSetFeatures* siblingFeatures = descendantFeatures.maxDirectAdjac entSelectors ? &descendantFeatures : nullptr; | |
| 675 | |
| 676 const CSSSelector* compound = &selector; | |
| 677 while (compound) { | |
| 678 const CSSSelector* lastInCompound = addFeaturesToInvalidationSetsForComp oundSelector(*compound, siblingFeatures, descendantFeatures); | |
| 679 DCHECK(lastInCompound); | |
| 680 updateFeaturesFromCombinator(*lastInCompound, compound, lastCompoundInSi blingChainFeatures, siblingFeatures, descendantFeatures); | |
| 681 compound = lastInCompound->tagHistory(); | |
| 682 } | |
| 621 } | 683 } |
| 622 | 684 |
| 623 RuleFeatureSet::SelectorPreMatch RuleFeatureSet::collectFeaturesFromRuleData(con st RuleData& ruleData) | 685 RuleFeatureSet::SelectorPreMatch RuleFeatureSet::collectFeaturesFromRuleData(con st RuleData& ruleData) |
| 624 { | 686 { |
| 625 RELEASE_ASSERT(m_isAlive); | 687 RELEASE_ASSERT(m_isAlive); |
| 626 FeatureMetadata metadata; | 688 FeatureMetadata metadata; |
| 627 if (collectFeaturesFromSelector(ruleData.selector(), metadata) == SelectorNe verMatches) | 689 if (collectFeaturesFromSelector(ruleData.selector(), metadata) == SelectorNe verMatches) |
| 628 return SelectorNeverMatches; | 690 return SelectorNeverMatches; |
| 629 | 691 |
| 630 m_metadata.add(metadata); | 692 m_metadata.add(metadata); |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 699 && ((relation != CSSSelector::SubSelector) || current->isLastInTagHi story())) { | 761 && ((relation != CSSSelector::SubSelector) || current->isLastInTagHi story())) { |
| 700 if (maxDirectAdjacentSelectors > metadata.maxDirectAdjacentSelectors ) | 762 if (maxDirectAdjacentSelectors > metadata.maxDirectAdjacentSelectors ) |
| 701 metadata.maxDirectAdjacentSelectors = maxDirectAdjacentSelectors ; | 763 metadata.maxDirectAdjacentSelectors = maxDirectAdjacentSelectors ; |
| 702 maxDirectAdjacentSelectors = 0; | 764 maxDirectAdjacentSelectors = 0; |
| 703 } | 765 } |
| 704 | 766 |
| 705 if (!metadata.foundInsertionPointCrossing && current->isAdjacentSelector ()) | 767 if (!metadata.foundInsertionPointCrossing && current->isAdjacentSelector ()) |
| 706 metadata.foundSiblingSelector = true; | 768 metadata.foundSiblingSelector = true; |
| 707 } | 769 } |
| 708 | 770 |
| 709 ASSERT(!maxDirectAdjacentSelectors); | 771 DCHECK(!maxDirectAdjacentSelectors); |
| 710 return SelectorMayMatch; | 772 return SelectorMayMatch; |
| 711 } | 773 } |
| 712 | 774 |
| 713 void RuleFeatureSet::FeatureMetadata::add(const FeatureMetadata& other) | 775 void RuleFeatureSet::FeatureMetadata::add(const FeatureMetadata& other) |
| 714 { | 776 { |
| 715 usesFirstLineRules = usesFirstLineRules || other.usesFirstLineRules; | 777 usesFirstLineRules = usesFirstLineRules || other.usesFirstLineRules; |
| 716 usesWindowInactiveSelector = usesWindowInactiveSelector || other.usesWindowI nactiveSelector; | 778 usesWindowInactiveSelector = usesWindowInactiveSelector || other.usesWindowI nactiveSelector; |
| 717 maxDirectAdjacentSelectors = std::max(maxDirectAdjacentSelectors, other.maxD irectAdjacentSelectors); | 779 maxDirectAdjacentSelectors = std::max(maxDirectAdjacentSelectors, other.maxD irectAdjacentSelectors); |
| 718 } | 780 } |
| 719 | 781 |
| (...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 938 else | 1000 else |
| 939 addFeaturesToInvalidationSet(universalSet.ensureSiblingDescendants(), de scendantFeatures); | 1001 addFeaturesToInvalidationSet(universalSet.ensureSiblingDescendants(), de scendantFeatures); |
| 940 } | 1002 } |
| 941 | 1003 |
| 942 DEFINE_TRACE(RuleFeatureSet) | 1004 DEFINE_TRACE(RuleFeatureSet) |
| 943 { | 1005 { |
| 944 visitor->trace(siblingRules); | 1006 visitor->trace(siblingRules); |
| 945 visitor->trace(uncommonAttributeRules); | 1007 visitor->trace(uncommonAttributeRules); |
| 946 } | 1008 } |
| 947 | 1009 |
| 1010 void RuleFeatureSet::InvalidationSetFeatures::add(const InvalidationSetFeatures& other) | |
| 1011 { | |
| 1012 classes.appendVector(other.classes); | |
| 1013 attributes.appendVector(other.attributes); | |
| 1014 ids.appendVector(other.ids); | |
| 1015 tagNames.appendVector(other.tagNames); | |
| 1016 maxDirectAdjacentSelectors = std::max(maxDirectAdjacentSelectors, other.maxD irectAdjacentSelectors); | |
| 1017 customPseudoElement |= other.customPseudoElement; | |
| 1018 hasBeforeOrAfter |= other.hasBeforeOrAfter; | |
| 1019 treeBoundaryCrossing |= other.treeBoundaryCrossing; | |
| 1020 insertionPointCrossing |= other.insertionPointCrossing; | |
| 1021 forceSubtree |= other.forceSubtree; | |
| 1022 contentPseudoCrossing |= other.contentPseudoCrossing; | |
| 1023 invalidatesSlotted |= other.invalidatesSlotted; | |
| 1024 hasNthPseudo |= other.hasNthPseudo; | |
| 1025 } | |
| 1026 | |
| 1027 bool RuleFeatureSet::InvalidationSetFeatures::hasFeatures() const | |
| 1028 { | |
| 1029 return !classes.isEmpty() | |
| 1030 || !attributes.isEmpty() | |
| 1031 || !ids.isEmpty() | |
| 1032 || !tagNames.isEmpty() | |
| 1033 || customPseudoElement; | |
| 1034 } | |
| 1035 | |
| 948 } // namespace blink | 1036 } // namespace blink |
| OLD | NEW |