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

Side by Side Diff: Source/core/css/SelectorChecker.cpp

Issue 334263020: Refactor SelectorChecker::BehaviorAtBoundary (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 6 years, 6 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 | Annotate | Revision Log
« no previous file with comments | « Source/core/css/SelectorChecker.h ('k') | Source/core/css/TreeBoundaryCrossingRules.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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, 2013 Apple Inc. All rights reserved. 5 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All rights 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 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
71 ShadowRoot* root = element->containingShadowRoot(); 71 ShadowRoot* root = element->containingShadowRoot();
72 if (!root || root->type() != ShadowRoot::UserAgentShadowRoot) 72 if (!root || root->type() != ShadowRoot::UserAgentShadowRoot)
73 return false; 73 return false;
74 74
75 if (element->shadowPseudoId() != selector.value()) 75 if (element->shadowPseudoId() != selector.value())
76 return false; 76 return false;
77 77
78 return true; 78 return true;
79 } 79 }
80 80
81 Element* SelectorChecker::parentElement(const SelectorCheckingContext& context, bool allowToCrossBoundary) const 81 static Element* parentElement(const SelectorChecker::SelectorCheckingContext& co ntext)
82 { 82 {
83 // CrossesBoundary means we don't care any context.scope. So we can walk up from a shadow root to its shadow host. 83 // If context.scope is a shadow root, we should walk up to its shadow host.
84 if (allowToCrossBoundary) 84 if (context.scope && context.scope == context.element->containingShadowRoot( ))
esprehn 2014/06/27 08:05:51 Why don't we need the ScopeIsShadowRoot stuff anym
kochi 2014/06/30 02:44:06 The flag used to mean that a context's scope was s
85 return context.element->parentOrShadowHostElement(); 85 return context.element->parentOrShadowHostElement();
86 86
87 // If context.scope is a shadow root, we should walk up to its shadow host.
88 if ((context.behaviorAtBoundary & SelectorChecker::ScopeIsShadowRoot) && con text.scope == context.element->containingShadowRoot())
89 return context.element->parentOrShadowHostElement();
90
91 if ((context.behaviorAtBoundary & SelectorChecker::BoundaryBehaviorMask) != SelectorChecker::StaysWithinTreeScope)
esprehn 2014/06/27 08:05:51 Why is this not needed now?
kochi 2014/06/30 02:44:06 Now the condition will never be met. This conditi
92 return context.element->parentElement();
93
94 // If context.scope is some element in some shadow tree and querySelector in itialized the context, 87 // If context.scope is some element in some shadow tree and querySelector in itialized the context,
95 // e.g. shadowRoot.querySelector(':host *'), 88 // e.g. shadowRoot.querySelector(':host *'),
96 // (a) context.element has the same treescope as context.scope, need to walk up to its shadow host. 89 // (a) context.element has the same treescope as context.scope, need to walk up to its shadow host.
97 // (b) Otherwise, should not walk up from a shadow root to a shadow host. 90 // (b) Otherwise, should not walk up from a shadow root to a shadow host.
98 if (context.scope && context.scope->treeScope() == context.element->treeScop e()) 91 if (context.scope && context.scope->treeScope() == context.element->treeScop e())
99 return context.element->parentOrShadowHostElement(); 92 return context.element->parentOrShadowHostElement();
100 93
101 return context.element->parentElement(); 94 return context.element->parentElement();
102 } 95 }
103 96
104 bool SelectorChecker::scopeContainsLastMatchedElement(const SelectorCheckingCont ext& context) const 97 static bool scopeContainsLastMatchedElement(const SelectorChecker::SelectorCheck ingContext& context)
105 { 98 {
106 if (!(context.behaviorAtBoundary & SelectorChecker::ScopeContainsLastMatched Element)) 99 if (!(context.contextFlags & SelectorChecker::ScopeContainsLastMatchedElemen t))
107 return true; 100 return true;
108 101
109 ASSERT(context.scope); 102 ASSERT(context.scope);
110 // If behaviorAtBoundary is not ScopeIsShadowRoot, we can use "contains". 103 // If the scope is not a Shadow root, we can use "contains".
111 if (!(context.behaviorAtBoundary & SelectorChecker::ScopeIsShadowRoot)) 104 if (!context.scope->isShadowRoot())
112 return context.scope->contains(context.element); 105 return context.scope->contains(context.element);
113 106
114 // If a given element is scope, i.e. shadow host, matches. 107 // If a given element is scope, i.e. shadow host, matches.
115 if (context.element == context.scope->shadowHost() && (!context.previousElem ent || context.previousElement->isInDescendantTreeOf(context.element))) 108 if (context.element == context.scope->shadowHost() && (!context.previousElem ent || context.previousElement->isInDescendantTreeOf(context.element)))
116 return true; 109 return true;
117 110
118 ShadowRoot* root = context.element->containingShadowRoot(); 111 // If the containing shadow root is scope, matches.
119 if (!root) 112 return context.element->containingShadowRoot() == context.scope;
120 return false;
121
122 // If a host of the containing shadow root is scope, matches.
123 return root == context.scope;
124 } 113 }
125 114
126 static inline bool nextSelectorExceedsScope(const SelectorChecker::SelectorCheck ingContext& context) 115 static inline bool nextSelectorExceedsScope(const SelectorChecker::SelectorCheck ingContext& context)
127 { 116 {
128 if (context.scope && context.scope->isInShadowTree()) 117 if (context.scope && context.scope->isInShadowTree())
129 return context.element == context.scope->shadowHost(); 118 return context.element == context.scope->shadowHost();
130 119
131 return false; 120 return false;
132 } 121 }
133 122
(...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after
334 for (; nextContext.element; nextContext.element = ElementTraversal::prev iousSibling(*nextContext.element)) { 323 for (; nextContext.element; nextContext.element = ElementTraversal::prev iousSibling(*nextContext.element)) {
335 Match match = this->match(nextContext, siblingTraversalStrategy, res ult); 324 Match match = this->match(nextContext, siblingTraversalStrategy, res ult);
336 if (match == SelectorMatches || match == SelectorFailsAllSiblings || match == SelectorFailsCompletely) 325 if (match == SelectorMatches || match == SelectorFailsAllSiblings || match == SelectorFailsCompletely)
337 return match; 326 return match;
338 }; 327 };
339 return SelectorFailsAllSiblings; 328 return SelectorFailsAllSiblings;
340 329
341 case CSSSelector::ShadowPseudo: 330 case CSSSelector::ShadowPseudo:
342 { 331 {
343 // If we're in the same tree-scope as the scoping element, then foll owing a shadow descendant combinator would escape that and thus the scope. 332 // If we're in the same tree-scope as the scoping element, then foll owing a shadow descendant combinator would escape that and thus the scope.
344 if (context.scope && context.scope->shadowHost() && context.scope->s hadowHost()->treeScope() == context.element->treeScope() && (context.behaviorAtB oundary & BoundaryBehaviorMask) != StaysWithinTreeScope) 333 if (context.scope && context.scope->shadowHost() && context.scope->s hadowHost()->treeScope() == context.element->treeScope())
345 return SelectorFailsCompletely; 334 return SelectorFailsCompletely;
346 335
347 Element* shadowHost = context.element->shadowHost(); 336 Element* shadowHost = context.element->shadowHost();
348 if (!shadowHost) 337 if (!shadowHost)
349 return SelectorFailsCompletely; 338 return SelectorFailsCompletely;
350 nextContext.element = shadowHost; 339 nextContext.element = shadowHost;
351 nextContext.isSubSelector = false; 340 nextContext.isSubSelector = false;
352 nextContext.elementStyle = 0; 341 nextContext.elementStyle = 0;
353 return this->match(nextContext, siblingTraversalStrategy, result); 342 return this->match(nextContext, siblingTraversalStrategy, result);
354 } 343 }
355 344
356 case CSSSelector::ShadowDeep: 345 case CSSSelector::ShadowDeep:
357 { 346 {
358 nextContext.isSubSelector = false; 347 nextContext.isSubSelector = false;
359 nextContext.elementStyle = 0; 348 nextContext.elementStyle = 0;
360 for (nextContext.element = parentElement(context, true); nextContext .element; nextContext.element = parentElement(nextContext, true)) { 349 for (nextContext.element = context.element->parentOrShadowHostElemen t(); nextContext.element; nextContext.element = nextContext.element->parentOrSha dowHostElement()) {
361 Match match = this->match(nextContext, siblingTraversalStrategy, result); 350 Match match = this->match(nextContext, siblingTraversalStrategy, result);
362 if (match == SelectorMatches || match == SelectorFailsCompletely ) 351 if (match == SelectorMatches || match == SelectorFailsCompletely )
363 return match; 352 return match;
364 if (nextSelectorExceedsScope(nextContext)) 353 if (nextSelectorExceedsScope(nextContext))
365 return SelectorFailsCompletely; 354 return SelectorFailsCompletely;
366 } 355 }
367 return SelectorFailsCompletely; 356 return SelectorFailsCompletely;
368 } 357 }
369 358
370 case CSSSelector::SubSelector: 359 case CSSSelector::SubSelector:
371 ASSERT_NOT_REACHED(); 360 ASSERT_NOT_REACHED();
372 } 361 }
373 362
374 ASSERT_NOT_REACHED(); 363 ASSERT_NOT_REACHED();
375 return SelectorFailsCompletely; 364 return SelectorFailsCompletely;
376 } 365 }
377 366
378 template<typename SiblingTraversalStrategy> 367 template<typename SiblingTraversalStrategy>
379 SelectorChecker::Match SelectorChecker::matchForShadowDistributed(const Element* element, const SiblingTraversalStrategy& siblingTraversalStrategy, SelectorChec kingContext& nextContext, MatchResult* result) const 368 SelectorChecker::Match SelectorChecker::matchForShadowDistributed(const Element* element, const SiblingTraversalStrategy& siblingTraversalStrategy, SelectorChec kingContext& nextContext, MatchResult* result) const
380 { 369 {
381 ASSERT(element); 370 ASSERT(element);
382 WillBeHeapVector<RawPtrWillBeMember<InsertionPoint>, 8> insertionPoints; 371 WillBeHeapVector<RawPtrWillBeMember<InsertionPoint>, 8> insertionPoints;
383
384 const ContainerNode* scope = nextContext.scope;
385 BehaviorAtBoundary behaviorAtBoundary = nextContext.behaviorAtBoundary;
386
387 collectDestinationInsertionPoints(*element, insertionPoints); 372 collectDestinationInsertionPoints(*element, insertionPoints);
388 for (size_t i = 0; i < insertionPoints.size(); ++i) { 373 for (size_t i = 0; i < insertionPoints.size(); ++i) {
389 nextContext.element = insertionPoints[i]; 374 nextContext.element = insertionPoints[i];
390 375 if (m_mode == SharingRules)
391 // If a given scope is a shadow host of an insertion point but behaviorA tBoundary doesn't have ScopeIsShadowRoot,
392 // we need to update behaviorAtBoundary to make selectors like ":host > ::content" work correctly.
393 if (m_mode == SharingRules) {
394 nextContext.behaviorAtBoundary = static_cast<BehaviorAtBoundary>(beh aviorAtBoundary | ScopeIsShadowRoot);
395 nextContext.scope = insertionPoints[i]->containingShadowRoot(); 376 nextContext.scope = insertionPoints[i]->containingShadowRoot();
396 } else if (scope == insertionPoints[i]->containingShadowRoot() && !(beha viorAtBoundary & ScopeIsShadowRoot)) {
397 nextContext.behaviorAtBoundary = static_cast<BehaviorAtBoundary>(beh aviorAtBoundary | ScopeIsShadowRoot);
398 } else {
399 nextContext.behaviorAtBoundary = behaviorAtBoundary;
400 }
401
402 nextContext.isSubSelector = false; 377 nextContext.isSubSelector = false;
403 nextContext.elementStyle = 0; 378 nextContext.elementStyle = 0;
404 if (match(nextContext, siblingTraversalStrategy, result) == SelectorMatc hes) 379 if (match(nextContext, siblingTraversalStrategy, result) == SelectorMatc hes)
405 return SelectorMatches; 380 return SelectorMatches;
406 } 381 }
407 return SelectorFailsLocally; 382 return SelectorFailsLocally;
408 } 383 }
409 384
410 template<typename CharType> 385 template<typename CharType>
411 static inline bool containsHTMLSpaceTemplate(const CharType* string, unsigned le ngth) 386 static inline bool containsHTMLSpaceTemplate(const CharType* string, unsigned le ngth)
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
527 } 502 }
528 503
529 template<typename SiblingTraversalStrategy> 504 template<typename SiblingTraversalStrategy>
530 bool SelectorChecker::checkOne(const SelectorCheckingContext& context, const Sib lingTraversalStrategy& siblingTraversalStrategy, unsigned* specificity) const 505 bool SelectorChecker::checkOne(const SelectorCheckingContext& context, const Sib lingTraversalStrategy& siblingTraversalStrategy, unsigned* specificity) const
531 { 506 {
532 ASSERT(context.element); 507 ASSERT(context.element);
533 Element& element = *context.element; 508 Element& element = *context.element;
534 ASSERT(context.selector); 509 ASSERT(context.selector);
535 const CSSSelector& selector = *context.selector; 510 const CSSSelector& selector = *context.selector;
536 511
537 bool elementIsHostInItsShadowTree = isHostInItsShadowTree(element, context.b ehaviorAtBoundary, context.scope); 512 bool elementIsHostInItsShadowTree = isHostInItsShadowTree(element, context.s cope);
538 513
539 // Only :host and :ancestor should match the host: http://drafts.csswg.org/c ss-scoping/#host-element 514 // Only :host and :ancestor should match the host: http://drafts.csswg.org/c ss-scoping/#host-element
540 if (elementIsHostInItsShadowTree && !selector.isHostPseudoClass() 515 if (elementIsHostInItsShadowTree && !selector.isHostPseudoClass()
541 && !(context.behaviorAtBoundary & TreatShadowHostAsNormalScope)) 516 && !(context.contextFlags & TreatShadowHostAsNormalScope))
542 return false; 517 return false;
543 518
544 if (selector.match() == CSSSelector::Tag) 519 if (selector.match() == CSSSelector::Tag)
545 return SelectorChecker::tagMatches(element, selector.tagQName()); 520 return SelectorChecker::tagMatches(element, selector.tagQName());
546 521
547 if (selector.match() == CSSSelector::Class) 522 if (selector.match() == CSSSelector::Class)
548 return element.hasClass() && element.classNames().contains(selector.valu e()); 523 return element.hasClass() && element.classNames().contains(selector.valu e());
549 524
550 if (selector.match() == CSSSelector::Id) 525 if (selector.match() == CSSSelector::Id)
551 return element.hasID() && element.idForStyleResolution() == selector.val ue(); 526 return element.hasID() && element.idForStyleResolution() == selector.val ue();
(...skipping 388 matching lines...) Expand 10 before | Expand all | Expand 10 after
940 return true; 915 return true;
941 916
942 SelectorCheckingContext subContext(context); 917 SelectorCheckingContext subContext(context);
943 subContext.isSubSelector = true; 918 subContext.isSubSelector = true;
944 919
945 bool matched = false; 920 bool matched = false;
946 unsigned maxSpecificity = 0; 921 unsigned maxSpecificity = 0;
947 922
948 // If one of simple selectors matches an element, returns Select orMatches. Just "OR". 923 // If one of simple selectors matches an element, returns Select orMatches. Just "OR".
949 for (subContext.selector = selector.selectorList()->first(); sub Context.selector; subContext.selector = CSSSelectorList::next(*subContext.select or)) { 924 for (subContext.selector = selector.selectorList()->first(); sub Context.selector; subContext.selector = CSSSelectorList::next(*subContext.select or)) {
950 subContext.behaviorAtBoundary = ScopeIsShadowHostInPseudoHos tParameter; 925 subContext.contextFlags = TreatShadowHostAsNormalScope;
951 subContext.scope = context.scope; 926 subContext.scope = context.scope;
952 // Use NodeRenderingTraversal to traverse a composed ancesto r list of a given element. 927 // Use NodeRenderingTraversal to traverse a composed ancesto r list of a given element.
953 Element* nextElement = &element; 928 Element* nextElement = &element;
954 SelectorCheckingContext hostContext(subContext); 929 SelectorCheckingContext hostContext(subContext);
955 do { 930 do {
956 MatchResult subResult; 931 MatchResult subResult;
957 hostContext.element = nextElement; 932 hostContext.element = nextElement;
958 if (match(hostContext, siblingTraversalStrategy, &subRes ult) == SelectorMatches) { 933 if (match(hostContext, siblingTraversalStrategy, &subRes ult) == SelectorMatches) {
959 matched = true; 934 matched = true;
960 // Consider div:host(div:host(div:host(div:host...)) ). 935 // Consider div:host(div:host(div:host(div:host...)) ).
961 maxSpecificity = std::max(maxSpecificity, hostContex t.selector->specificity() + subResult.specificity); 936 maxSpecificity = std::max(maxSpecificity, hostContex t.selector->specificity() + subResult.specificity);
962 break; 937 break;
963 } 938 }
964 hostContext.behaviorAtBoundary = DoesNotCrossBoundary; 939 hostContext.contextFlags = DefaultBehavior;
965 hostContext.scope = 0; 940 hostContext.scope = 0;
966 941
967 if (selector.pseudoType() == CSSSelector::PseudoHost) 942 if (selector.pseudoType() == CSSSelector::PseudoHost)
968 break; 943 break;
969 944
970 hostContext.elementStyle = 0; 945 hostContext.elementStyle = 0;
971 nextElement = NodeRenderingTraversal::parentElement(next Element); 946 nextElement = NodeRenderingTraversal::parentElement(next Element);
972 } while (nextElement); 947 } while (nextElement);
973 } 948 }
974 if (matched) { 949 if (matched) {
(...skipping 19 matching lines...) Expand all
994 case CSSSelector::PseudoUnknown: 969 case CSSSelector::PseudoUnknown:
995 case CSSSelector::PseudoNotParsed: 970 case CSSSelector::PseudoNotParsed:
996 default: 971 default:
997 ASSERT_NOT_REACHED(); 972 ASSERT_NOT_REACHED();
998 break; 973 break;
999 } 974 }
1000 return false; 975 return false;
1001 } else if (selector.match() == CSSSelector::PseudoElement && selector.pseudo Type() == CSSSelector::PseudoCue) { 976 } else if (selector.match() == CSSSelector::PseudoElement && selector.pseudo Type() == CSSSelector::PseudoCue) {
1002 SelectorCheckingContext subContext(context); 977 SelectorCheckingContext subContext(context);
1003 subContext.isSubSelector = true; 978 subContext.isSubSelector = true;
1004 subContext.behaviorAtBoundary = StaysWithinTreeScope; 979 subContext.contextFlags = DefaultBehavior;
1005 980
1006 const CSSSelector* contextSelector = context.selector; 981 const CSSSelector* contextSelector = context.selector;
1007 ASSERT(contextSelector); 982 ASSERT(contextSelector);
1008 for (subContext.selector = contextSelector->selectorList()->first(); sub Context.selector; subContext.selector = CSSSelectorList::next(*subContext.select or)) { 983 for (subContext.selector = contextSelector->selectorList()->first(); sub Context.selector; subContext.selector = CSSSelectorList::next(*subContext.select or)) {
1009 if (match(subContext, siblingTraversalStrategy) == SelectorMatches) 984 if (match(subContext, siblingTraversalStrategy) == SelectorMatches)
1010 return true; 985 return true;
1011 } 986 }
1012 return false; 987 return false;
1013 } 988 }
1014 // ### add the rest of the checks... 989 // ### add the rest of the checks...
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after
1150 return element.focused() && isFrameFocused(element); 1125 return element.focused() && isFrameFocused(element);
1151 } 1126 }
1152 1127
1153 template 1128 template
1154 SelectorChecker::Match SelectorChecker::match(const SelectorCheckingContext&, co nst DOMSiblingTraversalStrategy&, MatchResult*) const; 1129 SelectorChecker::Match SelectorChecker::match(const SelectorCheckingContext&, co nst DOMSiblingTraversalStrategy&, MatchResult*) const;
1155 1130
1156 template 1131 template
1157 SelectorChecker::Match SelectorChecker::match(const SelectorCheckingContext&, co nst ShadowDOMSiblingTraversalStrategy&, MatchResult*) const; 1132 SelectorChecker::Match SelectorChecker::match(const SelectorCheckingContext&, co nst ShadowDOMSiblingTraversalStrategy&, MatchResult*) const;
1158 1133
1159 } 1134 }
OLDNEW
« no previous file with comments | « Source/core/css/SelectorChecker.h ('k') | Source/core/css/TreeBoundaryCrossingRules.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698