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, 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 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
76 | 76 |
77 return true; | 77 return true; |
78 } | 78 } |
79 | 79 |
80 Element* SelectorChecker::parentElement(const SelectorCheckingContext& context,
bool allowToCrossBoundary) const | 80 Element* SelectorChecker::parentElement(const SelectorCheckingContext& context,
bool allowToCrossBoundary) const |
81 { | 81 { |
82 // CrossesBoundary means we don't care any context.scope. So we can walk up
from a shadow root to its shadow host. | 82 // CrossesBoundary means we don't care any context.scope. So we can walk up
from a shadow root to its shadow host. |
83 if (allowToCrossBoundary) | 83 if (allowToCrossBoundary) |
84 return context.element->parentOrShadowHostElement(); | 84 return context.element->parentOrShadowHostElement(); |
85 | 85 |
86 // If context.scope is a shadow host, we should walk up from a shadow root t
o its shadow host. | 86 // If context.scope is a shadow root, we should walk up to its shadow host. |
87 if ((context.behaviorAtBoundary & SelectorChecker::ScopeIsShadowHost) && con
text.scope == context.element->shadowHost()) | 87 if ((context.behaviorAtBoundary & SelectorChecker::ScopeIsShadowRoot) && con
text.scope == context.element->containingShadowRoot()) |
88 return context.element->parentOrShadowHostElement(); | 88 return context.element->parentOrShadowHostElement(); |
89 | 89 |
90 if ((context.behaviorAtBoundary & SelectorChecker::BoundaryBehaviorMask) !=
SelectorChecker::StaysWithinTreeScope) | 90 if ((context.behaviorAtBoundary & SelectorChecker::BoundaryBehaviorMask) !=
SelectorChecker::StaysWithinTreeScope) |
91 return context.element->parentElement(); | 91 return context.element->parentElement(); |
92 | 92 |
93 // If context.scope is some element in some shadow tree and querySelector in
itialized the context, | 93 // If context.scope is some element in some shadow tree and querySelector in
itialized the context, |
94 // e.g. shadowRoot.querySelector(':host *'), | 94 // e.g. shadowRoot.querySelector(':host *'), |
95 // (a) context.element has the same treescope as context.scope, need to walk
up to its shadow host. | 95 // (a) context.element has the same treescope as context.scope, need to walk
up to its shadow host. |
96 // (b) Otherwise, should not walk up from a shadow root to a shadow host. | 96 // (b) Otherwise, should not walk up from a shadow root to a shadow host. |
97 if (context.scope && context.scope->treeScope() == context.element->treeScop
e()) | 97 if (context.scope && context.scope->treeScope() == context.element->treeScop
e()) |
98 return context.element->parentOrShadowHostElement(); | 98 return context.element->parentOrShadowHostElement(); |
99 | 99 |
100 return context.element->parentElement(); | 100 return context.element->parentElement(); |
101 } | 101 } |
102 | 102 |
103 bool SelectorChecker::scopeContainsLastMatchedElement(const SelectorCheckingCont
ext& context) const | 103 bool SelectorChecker::scopeContainsLastMatchedElement(const SelectorCheckingCont
ext& context) const |
104 { | 104 { |
105 if (!(context.behaviorAtBoundary & SelectorChecker::ScopeContainsLastMatched
Element)) | 105 if (!(context.behaviorAtBoundary & SelectorChecker::ScopeContainsLastMatched
Element)) |
106 return true; | 106 return true; |
107 | 107 |
108 ASSERT(context.scope); | 108 ASSERT(context.scope); |
109 // If behaviorAtBoundary is not ScopeIsShadowHost, we can use "contains". | 109 // If behaviorAtBoundary is not ScopeIsShadowRoot, we can use "contains". |
110 if (!(context.behaviorAtBoundary & SelectorChecker::ScopeIsShadowHost)) | 110 if (!(context.behaviorAtBoundary & SelectorChecker::ScopeIsShadowRoot)) |
111 return context.scope->contains(context.element); | 111 return context.scope->contains(context.element); |
112 | 112 |
113 // If a given element is scope, i.e. shadow host, matches. | 113 // If a given element is scope, i.e. shadow host, matches. |
114 if (context.element == context.scope && (!context.previousElement || context
.previousElement->isInDescendantTreeOf(context.element))) | 114 if (context.element == context.scope->shadowHost() && (!context.previousElem
ent || context.previousElement->isInDescendantTreeOf(context.element))) |
115 return true; | 115 return true; |
116 | 116 |
117 ShadowRoot* root = context.element->containingShadowRoot(); | 117 ShadowRoot* root = context.element->containingShadowRoot(); |
118 if (!root) | 118 if (!root) |
119 return false; | 119 return false; |
120 | 120 |
121 // If a host of the containing shadow root is scope, matches. | 121 // If a host of the containing shadow root is scope, matches. |
122 return root->host() == context.scope; | 122 return root == context.scope; |
123 } | 123 } |
124 | 124 |
125 static inline bool nextSelectorExceedsScope(const SelectorChecker::SelectorCheck
ingContext& context) | 125 static inline bool nextSelectorExceedsScope(const SelectorChecker::SelectorCheck
ingContext& context) |
126 { | 126 { |
127 if ((context.behaviorAtBoundary & SelectorChecker::BoundaryBehaviorMask) !=
SelectorChecker::StaysWithinTreeScope) | 127 if (context.scope && context.scope->isInShadowTree()) |
128 return context.element == context.scope; | 128 return context.element == context.scope->shadowHost(); |
129 | 129 |
130 if (context.scope && context.scope->isInShadowTree()) | |
131 return context.element == context.scope->containingShadowRoot()->host(); | |
132 return false; | 130 return false; |
133 } | 131 } |
134 | 132 |
135 // Recursive check of selectors and combinators | 133 // Recursive check of selectors and combinators |
136 // It can return 4 different values: | 134 // It can return 4 different values: |
137 // * SelectorMatches - the selector matches the element e | 135 // * SelectorMatches - the selector matches the element e |
138 // * SelectorFailsLocally - the selector fails for the element e | 136 // * SelectorFailsLocally - the selector fails for the element e |
139 // * SelectorFailsAllSiblings - the selector fails for e and any sibling of e | 137 // * SelectorFailsAllSiblings - the selector fails for e and any sibling of e |
140 // * SelectorFailsCompletely - the selector fails for e and any sibling or ance
stor of e | 138 // * SelectorFailsCompletely - the selector fails for e and any sibling or ance
stor of e |
141 template<typename SiblingTraversalStrategy> | 139 template<typename SiblingTraversalStrategy> |
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
335 for (; nextContext.element; nextContext.element = ElementTraversal::prev
iousSibling(*nextContext.element)) { | 333 for (; nextContext.element; nextContext.element = ElementTraversal::prev
iousSibling(*nextContext.element)) { |
336 Match match = this->match(nextContext, siblingTraversalStrategy, res
ult); | 334 Match match = this->match(nextContext, siblingTraversalStrategy, res
ult); |
337 if (match == SelectorMatches || match == SelectorFailsAllSiblings ||
match == SelectorFailsCompletely) | 335 if (match == SelectorMatches || match == SelectorFailsAllSiblings ||
match == SelectorFailsCompletely) |
338 return match; | 336 return match; |
339 }; | 337 }; |
340 return SelectorFailsAllSiblings; | 338 return SelectorFailsAllSiblings; |
341 | 339 |
342 case CSSSelector::ShadowPseudo: | 340 case CSSSelector::ShadowPseudo: |
343 { | 341 { |
344 // 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. | 342 // 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. |
345 if (context.scope && context.scope->treeScope() == context.element->
treeScope() && (context.behaviorAtBoundary & BoundaryBehaviorMask) != StaysWithi
nTreeScope) | 343 if (context.scope && context.scope->shadowHost() && context.scope->s
hadowHost()->treeScope() == context.element->treeScope() && (context.behaviorAtB
oundary & BoundaryBehaviorMask) != StaysWithinTreeScope) |
346 return SelectorFailsCompletely; | 344 return SelectorFailsCompletely; |
347 | 345 |
348 Element* shadowHost = context.element->shadowHost(); | 346 Element* shadowHost = context.element->shadowHost(); |
349 if (!shadowHost) | 347 if (!shadowHost) |
350 return SelectorFailsCompletely; | 348 return SelectorFailsCompletely; |
351 nextContext.element = shadowHost; | 349 nextContext.element = shadowHost; |
352 nextContext.isSubSelector = false; | 350 nextContext.isSubSelector = false; |
353 nextContext.elementStyle = 0; | 351 nextContext.elementStyle = 0; |
354 return this->match(nextContext, siblingTraversalStrategy, result); | 352 return this->match(nextContext, siblingTraversalStrategy, result); |
355 } | 353 } |
(...skipping 26 matching lines...) Expand all Loading... |
382 ASSERT(element); | 380 ASSERT(element); |
383 WillBeHeapVector<RawPtrWillBeMember<InsertionPoint>, 8> insertionPoints; | 381 WillBeHeapVector<RawPtrWillBeMember<InsertionPoint>, 8> insertionPoints; |
384 | 382 |
385 const ContainerNode* scope = nextContext.scope; | 383 const ContainerNode* scope = nextContext.scope; |
386 BehaviorAtBoundary behaviorAtBoundary = nextContext.behaviorAtBoundary; | 384 BehaviorAtBoundary behaviorAtBoundary = nextContext.behaviorAtBoundary; |
387 | 385 |
388 collectDestinationInsertionPoints(*element, insertionPoints); | 386 collectDestinationInsertionPoints(*element, insertionPoints); |
389 for (size_t i = 0; i < insertionPoints.size(); ++i) { | 387 for (size_t i = 0; i < insertionPoints.size(); ++i) { |
390 nextContext.element = insertionPoints[i]; | 388 nextContext.element = insertionPoints[i]; |
391 | 389 |
392 // If a given scope is a shadow host of an insertion point but behaviorA
tBoundary doesn't have ScopeIsShadowHost, | 390 // If a given scope is a shadow host of an insertion point but behaviorA
tBoundary doesn't have ScopeIsShadowRoot, |
393 // we need to update behaviorAtBoundary to make selectors like ":host >
::content" work correctly. | 391 // we need to update behaviorAtBoundary to make selectors like ":host >
::content" work correctly. |
394 if (m_mode == SharingRules) { | 392 if (m_mode == SharingRules) { |
395 nextContext.behaviorAtBoundary = static_cast<BehaviorAtBoundary>(beh
aviorAtBoundary | ScopeIsShadowHost); | 393 nextContext.behaviorAtBoundary = static_cast<BehaviorAtBoundary>(beh
aviorAtBoundary | ScopeIsShadowRoot); |
396 nextContext.scope = insertionPoints[i]->containingShadowRoot()->shad
owHost(); | 394 nextContext.scope = insertionPoints[i]->containingShadowRoot(); |
397 } else if (scope == insertionPoints[i]->containingShadowRoot()->shadowHo
st() && !(behaviorAtBoundary & ScopeIsShadowHost)) | 395 } else if (scope == insertionPoints[i]->containingShadowRoot() && !(beha
viorAtBoundary & ScopeIsShadowRoot)) { |
398 nextContext.behaviorAtBoundary = static_cast<BehaviorAtBoundary>(beh
aviorAtBoundary | ScopeIsShadowHost); | 396 nextContext.behaviorAtBoundary = static_cast<BehaviorAtBoundary>(beh
aviorAtBoundary | ScopeIsShadowRoot); |
399 else | 397 } else { |
400 nextContext.behaviorAtBoundary = behaviorAtBoundary; | 398 nextContext.behaviorAtBoundary = behaviorAtBoundary; |
| 399 } |
401 | 400 |
402 nextContext.isSubSelector = false; | 401 nextContext.isSubSelector = false; |
403 nextContext.elementStyle = 0; | 402 nextContext.elementStyle = 0; |
404 if (match(nextContext, siblingTraversalStrategy, result) == SelectorMatc
hes) | 403 if (match(nextContext, siblingTraversalStrategy, result) == SelectorMatc
hes) |
405 return SelectorMatches; | 404 return SelectorMatches; |
406 } | 405 } |
407 return SelectorFailsLocally; | 406 return SelectorFailsLocally; |
408 } | 407 } |
409 | 408 |
410 template<typename CharType> | 409 template<typename CharType> |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
530 bool SelectorChecker::checkOne(const SelectorCheckingContext& context, const Sib
lingTraversalStrategy& siblingTraversalStrategy, unsigned* specificity) const | 529 bool SelectorChecker::checkOne(const SelectorCheckingContext& context, const Sib
lingTraversalStrategy& siblingTraversalStrategy, unsigned* specificity) const |
531 { | 530 { |
532 ASSERT(context.element); | 531 ASSERT(context.element); |
533 Element& element = *context.element; | 532 Element& element = *context.element; |
534 ASSERT(context.selector); | 533 ASSERT(context.selector); |
535 const CSSSelector& selector = *context.selector; | 534 const CSSSelector& selector = *context.selector; |
536 | 535 |
537 bool elementIsHostInItsShadowTree = isHostInItsShadowTree(element, context.b
ehaviorAtBoundary, context.scope); | 536 bool elementIsHostInItsShadowTree = isHostInItsShadowTree(element, context.b
ehaviorAtBoundary, context.scope); |
538 | 537 |
539 // Only :host and :ancestor should match the host: http://drafts.csswg.org/c
ss-scoping/#host-element | 538 // Only :host and :ancestor should match the host: http://drafts.csswg.org/c
ss-scoping/#host-element |
540 if (elementIsHostInItsShadowTree && !selector.isHostPseudoClass()) | 539 if (elementIsHostInItsShadowTree && !selector.isHostPseudoClass() |
| 540 && !(context.behaviorAtBoundary & TreatShadowHostAsNormalScope)) |
541 return false; | 541 return false; |
542 | 542 |
543 if (selector.match() == CSSSelector::Tag) | 543 if (selector.match() == CSSSelector::Tag) |
544 return SelectorChecker::tagMatches(element, selector.tagQName()); | 544 return SelectorChecker::tagMatches(element, selector.tagQName()); |
545 | 545 |
546 if (selector.match() == CSSSelector::Class) | 546 if (selector.match() == CSSSelector::Class) |
547 return element.hasClass() && element.classNames().contains(selector.valu
e()); | 547 return element.hasClass() && element.classNames().contains(selector.valu
e()); |
548 | 548 |
549 if (selector.match() == CSSSelector::Id) | 549 if (selector.match() == CSSSelector::Id) |
550 return element.hasID() && element.idForStyleResolution() == selector.val
ue(); | 550 return element.hasID() && element.idForStyleResolution() == selector.val
ue(); |
(...skipping 371 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
922 break; | 922 break; |
923 | 923 |
924 case CSSSelector::PseudoHost: | 924 case CSSSelector::PseudoHost: |
925 case CSSSelector::PseudoHostContext: | 925 case CSSSelector::PseudoHostContext: |
926 { | 926 { |
927 if (m_mode == SharingRules) | 927 if (m_mode == SharingRules) |
928 return true; | 928 return true; |
929 // :host only matches a shadow host when :host is in a shadow tr
ee of the shadow host. | 929 // :host only matches a shadow host when :host is in a shadow tr
ee of the shadow host. |
930 if (!context.scope) | 930 if (!context.scope) |
931 return false; | 931 return false; |
932 const ContainerNode* shadowHost = (context.behaviorAtBoundary &
ScopeIsShadowHost) ? context.scope : (context.scope->isInShadowTree() ? context.
scope->shadowHost() : 0); | 932 const ContainerNode* shadowHost = context.scope->shadowHost(); |
933 if (!shadowHost || shadowHost != element) | 933 if (!shadowHost || shadowHost != element) |
934 return false; | 934 return false; |
935 ASSERT(element.shadow()); | 935 ASSERT(element.shadow()); |
936 | 936 |
937 // For empty parameter case, i.e. just :host or :host(). | 937 // For empty parameter case, i.e. just :host or :host(). |
938 if (!selector.selectorList()) // Use *'s specificity. So just 0. | 938 if (!selector.selectorList()) // Use *'s specificity. So just 0. |
939 return true; | 939 return true; |
940 | 940 |
941 SelectorCheckingContext subContext(context); | 941 SelectorCheckingContext subContext(context); |
942 subContext.isSubSelector = true; | 942 subContext.isSubSelector = true; |
943 | 943 |
944 bool matched = false; | 944 bool matched = false; |
945 unsigned maxSpecificity = 0; | 945 unsigned maxSpecificity = 0; |
946 | 946 |
947 // If one of simple selectors matches an element, returns Select
orMatches. Just "OR". | 947 // If one of simple selectors matches an element, returns Select
orMatches. Just "OR". |
948 for (subContext.selector = selector.selectorList()->first(); sub
Context.selector; subContext.selector = CSSSelectorList::next(*subContext.select
or)) { | 948 for (subContext.selector = selector.selectorList()->first(); sub
Context.selector; subContext.selector = CSSSelectorList::next(*subContext.select
or)) { |
949 subContext.behaviorAtBoundary = ScopeIsShadowHostInPseudoHos
tParameter; | 949 subContext.behaviorAtBoundary = ScopeIsShadowHostInPseudoHos
tParameter; |
950 subContext.scope = shadowHost; | 950 subContext.scope = context.scope; |
951 // Use NodeRenderingTraversal to traverse a composed ancesto
r list of a given element. | 951 // Use NodeRenderingTraversal to traverse a composed ancesto
r list of a given element. |
952 Element* nextElement = &element; | 952 Element* nextElement = &element; |
953 SelectorCheckingContext hostContext(subContext); | 953 SelectorCheckingContext hostContext(subContext); |
954 do { | 954 do { |
955 MatchResult subResult; | 955 MatchResult subResult; |
956 hostContext.element = nextElement; | 956 hostContext.element = nextElement; |
957 if (match(hostContext, siblingTraversalStrategy, &subRes
ult) == SelectorMatches) { | 957 if (match(hostContext, siblingTraversalStrategy, &subRes
ult) == SelectorMatches) { |
958 matched = true; | 958 matched = true; |
959 // Consider div:host(div:host(div:host(div:host...))
). | 959 // Consider div:host(div:host(div:host(div:host...))
). |
960 maxSpecificity = std::max(maxSpecificity, hostContex
t.selector->specificity() + subResult.specificity); | 960 maxSpecificity = std::max(maxSpecificity, hostContex
t.selector->specificity() + subResult.specificity); |
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1149 return element.focused() && isFrameFocused(element); | 1149 return element.focused() && isFrameFocused(element); |
1150 } | 1150 } |
1151 | 1151 |
1152 template | 1152 template |
1153 SelectorChecker::Match SelectorChecker::match(const SelectorCheckingContext&, co
nst DOMSiblingTraversalStrategy&, MatchResult*) const; | 1153 SelectorChecker::Match SelectorChecker::match(const SelectorCheckingContext&, co
nst DOMSiblingTraversalStrategy&, MatchResult*) const; |
1154 | 1154 |
1155 template | 1155 template |
1156 SelectorChecker::Match SelectorChecker::match(const SelectorCheckingContext&, co
nst ShadowDOMSiblingTraversalStrategy&, MatchResult*) const; | 1156 SelectorChecker::Match SelectorChecker::match(const SelectorCheckingContext&, co
nst ShadowDOMSiblingTraversalStrategy&, MatchResult*) const; |
1157 | 1157 |
1158 } | 1158 } |
OLD | NEW |