| 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 |