Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(124)

Side by Side Diff: third_party/WebKit/Source/core/css/RuleFeature.cpp

Issue 2305593002: Refactored invalidation set extraction. (Closed)
Patch Set: Fixed comment Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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 (extractInvalidationSetFeaturesFromCompound).
429 // Secondly, add those features to the invalidation sets for the features
430 // found in the other compound selectors (addFeaturesToInvalidationSets). If
431 // we find a feature in the right-most compound selector that requires a
432 // subtree 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
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();
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
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
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
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/css/RuleFeature.h ('k') | third_party/WebKit/Source/core/dom/shadow/SelectRuleFeatureSet.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698