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