| 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. |
| 6 * All rights reserved. |
| 6 * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org> | 7 * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org> |
| 7 * Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org> | 8 * 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/) | 9 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. |
| 10 * (http://www.torchmobile.com/) |
| 9 * Copyright (c) 2011, Code Aurora Forum. All rights reserved. | 11 * Copyright (c) 2011, Code Aurora Forum. All rights reserved. |
| 10 * Copyright (C) Research In Motion Limited 2011. All rights reserved. | 12 * Copyright (C) Research In Motion Limited 2011. All rights reserved. |
| 11 * | 13 * |
| 12 * This library is free software; you can redistribute it and/or | 14 * This library is free software; you can redistribute it and/or |
| 13 * modify it under the terms of the GNU Library General Public | 15 * modify it under the terms of the GNU Library General Public |
| 14 * License as published by the Free Software Foundation; either | 16 * License as published by the Free Software Foundation; either |
| 15 * version 2 of the License, or (at your option) any later version. | 17 * version 2 of the License, or (at your option) any later version. |
| 16 * | 18 * |
| 17 * This library is distributed in the hope that it will be useful, | 19 * This library is distributed in the hope that it will be useful, |
| 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 20 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 95 if (element.tagQName().localNameUpper() != tagQName.localNameUpper()) | 97 if (element.tagQName().localNameUpper() != tagQName.localNameUpper()) |
| 96 return false; | 98 return false; |
| 97 } | 99 } |
| 98 const AtomicString& namespaceURI = tagQName.namespaceURI(); | 100 const AtomicString& namespaceURI = tagQName.namespaceURI(); |
| 99 return namespaceURI == starAtom || namespaceURI == element.namespaceURI(); | 101 return namespaceURI == starAtom || namespaceURI == element.namespaceURI(); |
| 100 } | 102 } |
| 101 | 103 |
| 102 static Element* parentElement( | 104 static Element* parentElement( |
| 103 const SelectorChecker::SelectorCheckingContext& context) { | 105 const SelectorChecker::SelectorCheckingContext& context) { |
| 104 // - If context.scope is a shadow root, we should walk up to its shadow host. | 106 // - If context.scope is a shadow root, we should walk up to its shadow host. |
| 105 // - If context.scope is some element in some shadow tree and querySelector in
itialized the context, | 107 // - If context.scope is some element in some shadow tree and querySelector |
| 106 // e.g. shadowRoot.querySelector(':host *'), | 108 // initialized the context, e.g. shadowRoot.querySelector(':host *'), |
| 107 // (a) context.element has the same treescope as context.scope, need to walk
up to its shadow host. | 109 // (a) context.element has the same treescope as context.scope, need to walk |
| 110 // up to its shadow host. |
| 108 // (b) Otherwise, should not walk up from a shadow root to a shadow host. | 111 // (b) Otherwise, should not walk up from a shadow root to a shadow host. |
| 109 if (context.scope && | 112 if (context.scope && |
| 110 (context.scope == context.element->containingShadowRoot() || | 113 (context.scope == context.element->containingShadowRoot() || |
| 111 context.scope->treeScope() == context.element->treeScope())) | 114 context.scope->treeScope() == context.element->treeScope())) |
| 112 return context.element->parentOrShadowHostElement(); | 115 return context.element->parentOrShadowHostElement(); |
| 113 return context.element->parentElement(); | 116 return context.element->parentElement(); |
| 114 } | 117 } |
| 115 | 118 |
| 116 static const HTMLSlotElement* findSlotElementInScope( | 119 static const HTMLSlotElement* findSlotElementInScope( |
| 117 const SelectorChecker::SelectorCheckingContext& context) { | 120 const SelectorChecker::SelectorCheckingContext& context) { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 129 | 132 |
| 130 static bool scopeContainsLastMatchedElement( | 133 static bool scopeContainsLastMatchedElement( |
| 131 const SelectorChecker::SelectorCheckingContext& context) { | 134 const SelectorChecker::SelectorCheckingContext& context) { |
| 132 // If this context isn't scoped, skip checking. | 135 // If this context isn't scoped, skip checking. |
| 133 if (!context.scope) | 136 if (!context.scope) |
| 134 return true; | 137 return true; |
| 135 | 138 |
| 136 if (context.scope->treeScope() == context.element->treeScope()) | 139 if (context.scope->treeScope() == context.element->treeScope()) |
| 137 return true; | 140 return true; |
| 138 | 141 |
| 139 // Because Blink treats a shadow host's TreeScope as a separate one from its d
escendent shadow roots, | 142 // Because Blink treats a shadow host's TreeScope as a separate one from its |
| 140 // if the last matched element is a shadow host, the condition above isn't met
, even though it | 143 // descendent shadow roots, if the last matched element is a shadow host, the |
| 141 // should be. | 144 // condition above isn't met, even though it should be. |
| 142 return context.element == context.scope->ownerShadowHost() && | 145 return context.element == context.scope->ownerShadowHost() && |
| 143 (!context.previousElement || | 146 (!context.previousElement || |
| 144 context.previousElement->isInDescendantTreeOf(context.element)); | 147 context.previousElement->isInDescendantTreeOf(context.element)); |
| 145 } | 148 } |
| 146 | 149 |
| 147 static inline bool nextSelectorExceedsScope( | 150 static inline bool nextSelectorExceedsScope( |
| 148 const SelectorChecker::SelectorCheckingContext& context) { | 151 const SelectorChecker::SelectorCheckingContext& context) { |
| 149 if (context.scope && context.scope->isInShadowTree()) | 152 if (context.scope && context.scope->isInShadowTree()) |
| 150 return context.element == context.scope->ownerShadowHost(); | 153 return context.element == context.scope->ownerShadowHost(); |
| 151 | 154 |
| 152 return false; | 155 return false; |
| 153 } | 156 } |
| 154 | 157 |
| 155 static bool shouldMatchHoverOrActive( | 158 static bool shouldMatchHoverOrActive( |
| 156 const SelectorChecker::SelectorCheckingContext& context) { | 159 const SelectorChecker::SelectorCheckingContext& context) { |
| 157 // If we're in quirks mode, then :hover and :active should never match anchors
with no | 160 // If we're in quirks mode, then :hover and :active should never match anchors |
| 158 // href and *:hover and *:active should not match anything. This is specified
in | 161 // with no href and *:hover and *:active should not match anything. This is |
| 159 // https://quirks.spec.whatwg.org/#the-:active-and-:hover-quirk | 162 // specified in https://quirks.spec.whatwg.org/#the-:active-and-:hover-quirk |
| 160 if (!context.element->document().inQuirksMode()) | 163 if (!context.element->document().inQuirksMode()) |
| 161 return true; | 164 return true; |
| 162 if (context.isSubSelector) | 165 if (context.isSubSelector) |
| 163 return true; | 166 return true; |
| 164 if (context.element->isLink()) | 167 if (context.element->isLink()) |
| 165 return true; | 168 return true; |
| 166 const CSSSelector* selector = context.selector; | 169 const CSSSelector* selector = context.selector; |
| 167 while (selector->relation() == CSSSelector::SubSelector && | 170 while (selector->relation() == CSSSelector::SubSelector && |
| 168 selector->tagHistory()) { | 171 selector->tagHistory()) { |
| 169 selector = selector->tagHistory(); | 172 selector = selector->tagHistory(); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 190 | 193 |
| 191 static bool isLastOfType(Element& element, const QualifiedName& type) { | 194 static bool isLastOfType(Element& element, const QualifiedName& type) { |
| 192 return !ElementTraversal::nextSibling(element, HasTagName(type)); | 195 return !ElementTraversal::nextSibling(element, HasTagName(type)); |
| 193 } | 196 } |
| 194 | 197 |
| 195 // Recursive check of selectors and combinators | 198 // Recursive check of selectors and combinators |
| 196 // It can return 4 different values: | 199 // It can return 4 different values: |
| 197 // * SelectorMatches - the selector matches the element e | 200 // * SelectorMatches - the selector matches the element e |
| 198 // * SelectorFailsLocally - the selector fails for the element e | 201 // * SelectorFailsLocally - the selector fails for the element e |
| 199 // * SelectorFailsAllSiblings - the selector fails for e and any sibling of e | 202 // * SelectorFailsAllSiblings - the selector fails for e and any sibling of e |
| 200 // * SelectorFailsCompletely - the selector fails for e and any sibling or ance
stor of e | 203 // * SelectorFailsCompletely - the selector fails for e and any sibling or |
| 204 // ancestor of e |
| 201 SelectorChecker::Match SelectorChecker::matchSelector( | 205 SelectorChecker::Match SelectorChecker::matchSelector( |
| 202 const SelectorCheckingContext& context, | 206 const SelectorCheckingContext& context, |
| 203 MatchResult& result) const { | 207 MatchResult& result) const { |
| 204 MatchResult subResult; | 208 MatchResult subResult; |
| 205 if (!checkOne(context, subResult)) | 209 if (!checkOne(context, subResult)) |
| 206 return SelectorFailsLocally; | 210 return SelectorFailsLocally; |
| 207 | 211 |
| 208 if (subResult.dynamicPseudo != PseudoIdNone) | 212 if (subResult.dynamicPseudo != PseudoIdNone) |
| 209 result.dynamicPseudo = subResult.dynamicPseudo; | 213 result.dynamicPseudo = subResult.dynamicPseudo; |
| 210 | 214 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 232 } | 236 } |
| 233 if (match == SelectorMatches) | 237 if (match == SelectorMatches) |
| 234 result.specificity += subResult.specificity; | 238 result.specificity += subResult.specificity; |
| 235 return match; | 239 return match; |
| 236 } | 240 } |
| 237 | 241 |
| 238 static inline SelectorChecker::SelectorCheckingContext | 242 static inline SelectorChecker::SelectorCheckingContext |
| 239 prepareNextContextForRelation( | 243 prepareNextContextForRelation( |
| 240 const SelectorChecker::SelectorCheckingContext& context) { | 244 const SelectorChecker::SelectorCheckingContext& context) { |
| 241 SelectorChecker::SelectorCheckingContext nextContext(context); | 245 SelectorChecker::SelectorCheckingContext nextContext(context); |
| 242 ASSERT(context.selector->tagHistory()); | 246 DCHECK(context.selector->tagHistory()); |
| 243 nextContext.selector = context.selector->tagHistory(); | 247 nextContext.selector = context.selector->tagHistory(); |
| 244 return nextContext; | 248 return nextContext; |
| 245 } | 249 } |
| 246 | 250 |
| 247 SelectorChecker::Match SelectorChecker::matchForSubSelector( | 251 SelectorChecker::Match SelectorChecker::matchForSubSelector( |
| 248 const SelectorCheckingContext& context, | 252 const SelectorCheckingContext& context, |
| 249 MatchResult& result) const { | 253 MatchResult& result) const { |
| 250 SelectorCheckingContext nextContext = prepareNextContextForRelation(context); | 254 SelectorCheckingContext nextContext = prepareNextContextForRelation(context); |
| 251 | 255 |
| 252 PseudoId dynamicPseudo = result.dynamicPseudo; | 256 PseudoId dynamicPseudo = result.dynamicPseudo; |
| (...skipping 30 matching lines...) Expand all Loading... |
| 283 return element.parentOrShadowHostElement(); | 287 return element.parentOrShadowHostElement(); |
| 284 } | 288 } |
| 285 | 289 |
| 286 SelectorChecker::Match SelectorChecker::matchForRelation( | 290 SelectorChecker::Match SelectorChecker::matchForRelation( |
| 287 const SelectorCheckingContext& context, | 291 const SelectorCheckingContext& context, |
| 288 MatchResult& result) const { | 292 MatchResult& result) const { |
| 289 SelectorCheckingContext nextContext = prepareNextContextForRelation(context); | 293 SelectorCheckingContext nextContext = prepareNextContextForRelation(context); |
| 290 | 294 |
| 291 CSSSelector::RelationType relation = context.selector->relation(); | 295 CSSSelector::RelationType relation = context.selector->relation(); |
| 292 | 296 |
| 293 // Disable :visited matching when we see the first link or try to match anythi
ng else than an ancestors. | 297 // Disable :visited matching when we see the first link or try to match |
| 298 // anything else than an ancestors. |
| 294 if (!context.isSubSelector && | 299 if (!context.isSubSelector && |
| 295 (context.element->isLink() || | 300 (context.element->isLink() || |
| 296 (relation != CSSSelector::Descendant && relation != CSSSelector::Child))) | 301 (relation != CSSSelector::Descendant && relation != CSSSelector::Child))) |
| 297 nextContext.visitedMatchType = VisitedMatchDisabled; | 302 nextContext.visitedMatchType = VisitedMatchDisabled; |
| 298 | 303 |
| 299 nextContext.inRightmostCompound = false; | 304 nextContext.inRightmostCompound = false; |
| 300 nextContext.isSubSelector = false; | 305 nextContext.isSubSelector = false; |
| 301 nextContext.previousElement = context.element; | 306 nextContext.previousElement = context.element; |
| 302 nextContext.pseudoId = PseudoIdNone; | 307 nextContext.pseudoId = PseudoIdNone; |
| 303 | 308 |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 373 match == SelectorFailsCompletely) | 378 match == SelectorFailsCompletely) |
| 374 return match; | 379 return match; |
| 375 } | 380 } |
| 376 return SelectorFailsAllSiblings; | 381 return SelectorFailsAllSiblings; |
| 377 | 382 |
| 378 case CSSSelector::ShadowPseudo: { | 383 case CSSSelector::ShadowPseudo: { |
| 379 if (!m_isUARule && !m_isQuerySelector && | 384 if (!m_isUARule && !m_isQuerySelector && |
| 380 context.selector->getPseudoType() == CSSSelector::PseudoShadow) | 385 context.selector->getPseudoType() == CSSSelector::PseudoShadow) |
| 381 Deprecation::countDeprecation(context.element->document(), | 386 Deprecation::countDeprecation(context.element->document(), |
| 382 UseCounter::CSSSelectorPseudoShadow); | 387 UseCounter::CSSSelectorPseudoShadow); |
| 383 // If we're in the same tree-scope as the scoping element, then following
a shadow descendant combinator would escape that and thus the scope. | 388 // If we're in the same tree-scope as the scoping element, then following |
| 389 // a shadow descendant combinator would escape that and thus the scope. |
| 384 if (context.scope && context.scope->ownerShadowHost() && | 390 if (context.scope && context.scope->ownerShadowHost() && |
| 385 context.scope->ownerShadowHost()->treeScope() == | 391 context.scope->ownerShadowHost()->treeScope() == |
| 386 context.element->treeScope()) | 392 context.element->treeScope()) |
| 387 return SelectorFailsCompletely; | 393 return SelectorFailsCompletely; |
| 388 | 394 |
| 389 Element* shadowHost = context.element->ownerShadowHost(); | 395 Element* shadowHost = context.element->ownerShadowHost(); |
| 390 if (!shadowHost) | 396 if (!shadowHost) |
| 391 return SelectorFailsCompletely; | 397 return SelectorFailsCompletely; |
| 392 nextContext.element = shadowHost; | 398 nextContext.element = shadowHost; |
| 393 return matchSelector(nextContext, result); | 399 return matchSelector(nextContext, result); |
| 394 } | 400 } |
| 395 | 401 |
| 396 case CSSSelector::ShadowDeep: { | 402 case CSSSelector::ShadowDeep: { |
| 397 if (!m_isUARule && !m_isQuerySelector) | 403 if (!m_isUARule && !m_isQuerySelector) |
| 398 Deprecation::countDeprecation(context.element->document(), | 404 Deprecation::countDeprecation(context.element->document(), |
| 399 UseCounter::CSSDeepCombinator); | 405 UseCounter::CSSDeepCombinator); |
| 400 if (ShadowRoot* root = context.element->containingShadowRoot()) { | 406 if (ShadowRoot* root = context.element->containingShadowRoot()) { |
| 401 if (root->type() == ShadowRootType::UserAgent) | 407 if (root->type() == ShadowRootType::UserAgent) |
| 402 return SelectorFailsCompletely; | 408 return SelectorFailsCompletely; |
| 403 } | 409 } |
| 404 | 410 |
| 405 if (context.selector->relationIsAffectedByPseudoContent()) { | 411 if (context.selector->relationIsAffectedByPseudoContent()) { |
| 406 // TODO(kochi): closed mode tree should be handled as well for ::content
. | 412 // TODO(kochi): closed mode tree should be handled as well for |
| 413 // ::content. |
| 407 for (Element* element = context.element; element; | 414 for (Element* element = context.element; element; |
| 408 element = element->parentOrShadowHostElement()) { | 415 element = element->parentOrShadowHostElement()) { |
| 409 if (matchForPseudoContent(nextContext, *element, result) == | 416 if (matchForPseudoContent(nextContext, *element, result) == |
| 410 SelectorMatches) { | 417 SelectorMatches) { |
| 411 if (context.element->isInShadowTree()) | 418 if (context.element->isInShadowTree()) |
| 412 UseCounter::count(context.element->document(), | 419 UseCounter::count(context.element->document(), |
| 413 UseCounter::CSSDeepCombinatorAndShadow); | 420 UseCounter::CSSDeepCombinatorAndShadow); |
| 414 return SelectorMatches; | 421 return SelectorMatches; |
| 415 } | 422 } |
| 416 } | 423 } |
| (...skipping 21 matching lines...) Expand all Loading... |
| 438 if (!slot) | 445 if (!slot) |
| 439 return SelectorFailsCompletely; | 446 return SelectorFailsCompletely; |
| 440 | 447 |
| 441 nextContext.element = const_cast<HTMLSlotElement*>(slot); | 448 nextContext.element = const_cast<HTMLSlotElement*>(slot); |
| 442 return matchSelector(nextContext, result); | 449 return matchSelector(nextContext, result); |
| 443 } | 450 } |
| 444 | 451 |
| 445 case CSSSelector::SubSelector: | 452 case CSSSelector::SubSelector: |
| 446 break; | 453 break; |
| 447 } | 454 } |
| 448 ASSERT_NOT_REACHED(); | 455 NOTREACHED(); |
| 449 return SelectorFailsCompletely; | 456 return SelectorFailsCompletely; |
| 450 } | 457 } |
| 451 | 458 |
| 452 SelectorChecker::Match SelectorChecker::matchForPseudoContent( | 459 SelectorChecker::Match SelectorChecker::matchForPseudoContent( |
| 453 const SelectorCheckingContext& context, | 460 const SelectorCheckingContext& context, |
| 454 const Element& element, | 461 const Element& element, |
| 455 MatchResult& result) const { | 462 MatchResult& result) const { |
| 456 HeapVector<Member<InsertionPoint>, 8> insertionPoints; | 463 HeapVector<Member<InsertionPoint>, 8> insertionPoints; |
| 457 collectDestinationInsertionPoints(element, insertionPoints); | 464 collectDestinationInsertionPoints(element, insertionPoints); |
| 458 SelectorCheckingContext nextContext(context); | 465 SelectorCheckingContext nextContext(context); |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 522 if (value.length() < selectorValue.length()) | 529 if (value.length() < selectorValue.length()) |
| 523 return false; | 530 return false; |
| 524 if (!value.startsWith(selectorValue, caseSensitivity)) | 531 if (!value.startsWith(selectorValue, caseSensitivity)) |
| 525 return false; | 532 return false; |
| 526 // It they start the same, check for exact match or following '-': | 533 // It they start the same, check for exact match or following '-': |
| 527 if (value.length() != selectorValue.length() && | 534 if (value.length() != selectorValue.length() && |
| 528 value[selectorValue.length()] != '-') | 535 value[selectorValue.length()] != '-') |
| 529 return false; | 536 return false; |
| 530 return true; | 537 return true; |
| 531 default: | 538 default: |
| 532 ASSERT_NOT_REACHED(); | 539 NOTREACHED(); |
| 533 return false; | 540 return false; |
| 534 } | 541 } |
| 535 } | 542 } |
| 536 | 543 |
| 537 static bool anyAttributeMatches(Element& element, | 544 static bool anyAttributeMatches(Element& element, |
| 538 CSSSelector::MatchType match, | 545 CSSSelector::MatchType match, |
| 539 const CSSSelector& selector) { | 546 const CSSSelector& selector) { |
| 540 const QualifiedName& selectorAttr = selector.attribute(); | 547 const QualifiedName& selectorAttr = selector.attribute(); |
| 541 ASSERT(selectorAttr.localName() != | 548 // Should not be possible from the CSS grammar. |
| 542 starAtom); // Should not be possible from the CSS grammar. | 549 DCHECK_NE(selectorAttr.localName(), starAtom); |
| 543 | 550 |
| 544 // Synchronize the attribute in case it is lazy-computed. | 551 // Synchronize the attribute in case it is lazy-computed. |
| 545 // Currently all lazy properties have a null namespace, so only pass localName
(). | 552 // Currently all lazy properties have a null namespace, so only pass |
| 553 // localName(). |
| 546 element.synchronizeAttribute(selectorAttr.localName()); | 554 element.synchronizeAttribute(selectorAttr.localName()); |
| 547 | 555 |
| 548 const AtomicString& selectorValue = selector.value(); | 556 const AtomicString& selectorValue = selector.value(); |
| 549 TextCaseSensitivity caseSensitivity = | 557 TextCaseSensitivity caseSensitivity = |
| 550 (selector.attributeMatch() == CSSSelector::CaseInsensitive) | 558 (selector.attributeMatch() == CSSSelector::CaseInsensitive) |
| 551 ? TextCaseASCIIInsensitive | 559 ? TextCaseASCIIInsensitive |
| 552 : TextCaseSensitive; | 560 : TextCaseSensitive; |
| 553 | 561 |
| 554 AttributeCollection attributes = element.attributesWithoutUpdate(); | 562 AttributeCollection attributes = element.attributesWithoutUpdate(); |
| 555 for (const auto& attributeItem : attributes) { | 563 for (const auto& attributeItem : attributes) { |
| (...skipping 28 matching lines...) Expand all Loading... |
| 584 } | 592 } |
| 585 if (selectorAttr.namespaceURI() != starAtom) | 593 if (selectorAttr.namespaceURI() != starAtom) |
| 586 return false; | 594 return false; |
| 587 } | 595 } |
| 588 | 596 |
| 589 return false; | 597 return false; |
| 590 } | 598 } |
| 591 | 599 |
| 592 bool SelectorChecker::checkOne(const SelectorCheckingContext& context, | 600 bool SelectorChecker::checkOne(const SelectorCheckingContext& context, |
| 593 MatchResult& result) const { | 601 MatchResult& result) const { |
| 594 ASSERT(context.element); | 602 DCHECK(context.element); |
| 595 Element& element = *context.element; | 603 Element& element = *context.element; |
| 596 ASSERT(context.selector); | 604 DCHECK(context.selector); |
| 597 const CSSSelector& selector = *context.selector; | 605 const CSSSelector& selector = *context.selector; |
| 598 | 606 |
| 599 // Only :host and :host-context() should match the host: http://drafts.csswg.o
rg/css-scoping/#host-element | 607 // Only :host and :host-context() should match the host: |
| 608 // http://drafts.csswg.org/css-scoping/#host-element |
| 600 if (context.scope && context.scope->ownerShadowHost() == element && | 609 if (context.scope && context.scope->ownerShadowHost() == element && |
| 601 (!selector.isHostPseudoClass() && !context.treatShadowHostAsNormalScope && | 610 (!selector.isHostPseudoClass() && !context.treatShadowHostAsNormalScope && |
| 602 selector.match() != CSSSelector::PseudoElement)) | 611 selector.match() != CSSSelector::PseudoElement)) |
| 603 return false; | 612 return false; |
| 604 | 613 |
| 605 switch (selector.match()) { | 614 switch (selector.match()) { |
| 606 case CSSSelector::Tag: | 615 case CSSSelector::Tag: |
| 607 return matchesTagName(element, selector.tagQName()); | 616 return matchesTagName(element, selector.tagQName()); |
| 608 case CSSSelector::Class: | 617 case CSSSelector::Class: |
| 609 return element.hasClass() && | 618 return element.hasClass() && |
| (...skipping 11 matching lines...) Expand all Loading... |
| 621 case CSSSelector::AttributeBegin: | 630 case CSSSelector::AttributeBegin: |
| 622 case CSSSelector::AttributeEnd: | 631 case CSSSelector::AttributeEnd: |
| 623 return anyAttributeMatches(element, selector.match(), selector); | 632 return anyAttributeMatches(element, selector.match(), selector); |
| 624 | 633 |
| 625 case CSSSelector::PseudoClass: | 634 case CSSSelector::PseudoClass: |
| 626 return checkPseudoClass(context, result); | 635 return checkPseudoClass(context, result); |
| 627 case CSSSelector::PseudoElement: | 636 case CSSSelector::PseudoElement: |
| 628 return checkPseudoElement(context, result); | 637 return checkPseudoElement(context, result); |
| 629 | 638 |
| 630 default: | 639 default: |
| 631 ASSERT_NOT_REACHED(); | 640 NOTREACHED(); |
| 632 return false; | 641 return false; |
| 633 } | 642 } |
| 634 } | 643 } |
| 635 | 644 |
| 636 bool SelectorChecker::checkPseudoNot(const SelectorCheckingContext& context, | 645 bool SelectorChecker::checkPseudoNot(const SelectorCheckingContext& context, |
| 637 MatchResult& result) const { | 646 MatchResult& result) const { |
| 638 const CSSSelector& selector = *context.selector; | 647 const CSSSelector& selector = *context.selector; |
| 639 | 648 |
| 640 SelectorCheckingContext subContext(context); | 649 SelectorCheckingContext subContext(context); |
| 641 subContext.isSubSelector = true; | 650 subContext.isSubSelector = true; |
| 642 ASSERT(selector.selectorList()); | 651 DCHECK(selector.selectorList()); |
| 643 for (subContext.selector = selector.selectorList()->first(); | 652 for (subContext.selector = selector.selectorList()->first(); |
| 644 subContext.selector; | 653 subContext.selector; |
| 645 subContext.selector = subContext.selector->tagHistory()) { | 654 subContext.selector = subContext.selector->tagHistory()) { |
| 646 // :not cannot nest. I don't really know why this is a | 655 // :not cannot nest. I don't really know why this is a |
| 647 // restriction in CSS3, but it is, so let's honor it. | 656 // restriction in CSS3, but it is, so let's honor it. |
| 648 // the parser enforces that this never occurs | 657 // the parser enforces that this never occurs |
| 649 ASSERT(subContext.selector->getPseudoType() != CSSSelector::PseudoNot); | 658 DCHECK_NE(subContext.selector->getPseudoType(), CSSSelector::PseudoNot); |
| 650 // We select between :visited and :link when applying. We don't know which o
ne applied (or not) yet. | 659 // We select between :visited and :link when applying. We don't know which |
| 660 // one applied (or not) yet. |
| 651 if (subContext.selector->getPseudoType() == CSSSelector::PseudoVisited || | 661 if (subContext.selector->getPseudoType() == CSSSelector::PseudoVisited || |
| 652 (subContext.selector->getPseudoType() == CSSSelector::PseudoLink && | 662 (subContext.selector->getPseudoType() == CSSSelector::PseudoLink && |
| 653 subContext.visitedMatchType == VisitedMatchEnabled)) | 663 subContext.visitedMatchType == VisitedMatchEnabled)) |
| 654 return true; | 664 return true; |
| 655 if (m_mode == SharingRules) { | 665 if (m_mode == SharingRules) { |
| 656 // context.scope is not available if m_mode == SharingRules. | 666 // context.scope is not available if m_mode == SharingRules. |
| 657 // We cannot determine whether :host or :scope matches a given element or
not. | 667 // We cannot determine whether :host or :scope matches a given element or |
| 668 // not. |
| 658 if (subContext.selector->isHostPseudoClass() || | 669 if (subContext.selector->isHostPseudoClass() || |
| 659 subContext.selector->getPseudoType() == CSSSelector::PseudoScope) | 670 subContext.selector->getPseudoType() == CSSSelector::PseudoScope) |
| 660 return true; | 671 return true; |
| 661 // :hover, :active, :focus, :-webkit-drag relies on setting flags on | 672 // :hover, :active, :focus, :-webkit-drag relies on setting flags on |
| 662 // ComputedStyle even if the whole selector may not match. That | 673 // ComputedStyle even if the whole selector may not match. That |
| 663 // means we cannot share style between elements which may fail | 674 // means we cannot share style between elements which may fail |
| 664 // matching the same selector for different reasons. An example is | 675 // matching the same selector for different reasons. An example is |
| 665 // [attr]:hover which both fail for :hover, but an element without | 676 // [attr]:hover which both fail for :hover, but an element without |
| 666 // attr won't reach the :hover selector, hence not setting the bit. | 677 // attr won't reach the :hover selector, hence not setting the bit. |
| 667 if (subContext.selector->isUserActionPseudoClass()) | 678 if (subContext.selector->isUserActionPseudoClass()) |
| 668 return true; | 679 return true; |
| 669 } | 680 } |
| 670 if (!checkOne(subContext, result)) | 681 if (!checkOne(subContext, result)) |
| 671 return true; | 682 return true; |
| 672 } | 683 } |
| 673 return false; | 684 return false; |
| 674 } | 685 } |
| 675 | 686 |
| 676 bool SelectorChecker::checkPseudoClass(const SelectorCheckingContext& context, | 687 bool SelectorChecker::checkPseudoClass(const SelectorCheckingContext& context, |
| 677 MatchResult& result) const { | 688 MatchResult& result) const { |
| 678 Element& element = *context.element; | 689 Element& element = *context.element; |
| 679 const CSSSelector& selector = *context.selector; | 690 const CSSSelector& selector = *context.selector; |
| 680 | 691 |
| 681 if (context.hasScrollbarPseudo) { | 692 if (context.hasScrollbarPseudo) { |
| 682 // CSS scrollbars match a specific subset of pseudo classes, and they have s
pecialized rules for each | 693 // CSS scrollbars match a specific subset of pseudo classes, and they have |
| 694 // specialized rules for each |
| 683 // (since there are no elements involved). | 695 // (since there are no elements involved). |
| 684 return checkScrollbarPseudoClass(context, result); | 696 return checkScrollbarPseudoClass(context, result); |
| 685 } | 697 } |
| 686 | 698 |
| 687 switch (selector.getPseudoType()) { | 699 switch (selector.getPseudoType()) { |
| 688 case CSSSelector::PseudoNot: | 700 case CSSSelector::PseudoNot: |
| 689 return checkPseudoNot(context, result); | 701 return checkPseudoNot(context, result); |
| 690 case CSSSelector::PseudoEmpty: { | 702 case CSSSelector::PseudoEmpty: { |
| 691 bool result = true; | 703 bool result = true; |
| 692 for (Node* n = element.firstChild(); n; n = n->nextSibling()) { | 704 for (Node* n = element.firstChild(); n; n = n->nextSibling()) { |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 809 if (!parent->isFinishedParsingChildren()) | 821 if (!parent->isFinishedParsingChildren()) |
| 810 return false; | 822 return false; |
| 811 return selector.matchNth(NthIndexCache::nthLastOfTypeIndex(element)); | 823 return selector.matchNth(NthIndexCache::nthLastOfTypeIndex(element)); |
| 812 } | 824 } |
| 813 break; | 825 break; |
| 814 case CSSSelector::PseudoTarget: | 826 case CSSSelector::PseudoTarget: |
| 815 return element == element.document().cssTarget(); | 827 return element == element.document().cssTarget(); |
| 816 case CSSSelector::PseudoAny: { | 828 case CSSSelector::PseudoAny: { |
| 817 SelectorCheckingContext subContext(context); | 829 SelectorCheckingContext subContext(context); |
| 818 subContext.isSubSelector = true; | 830 subContext.isSubSelector = true; |
| 819 ASSERT(selector.selectorList()); | 831 DCHECK(selector.selectorList()); |
| 820 for (subContext.selector = selector.selectorList()->first(); | 832 for (subContext.selector = selector.selectorList()->first(); |
| 821 subContext.selector; | 833 subContext.selector; |
| 822 subContext.selector = CSSSelectorList::next(*subContext.selector)) { | 834 subContext.selector = CSSSelectorList::next(*subContext.selector)) { |
| 823 if (match(subContext)) | 835 if (match(subContext)) |
| 824 return true; | 836 return true; |
| 825 } | 837 } |
| 826 } break; | 838 } break; |
| 827 case CSSSelector::PseudoAutofill: | 839 case CSSSelector::PseudoAutofill: |
| 828 return element.isFormControlElement() && | 840 return element.isFormControlElement() && |
| 829 toHTMLFormControlElement(element).isAutofilled(); | 841 toHTMLFormControlElement(element).isAutofilled(); |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 946 const AtomicString& argument = selector.argument(); | 958 const AtomicString& argument = selector.argument(); |
| 947 if (value.isEmpty() || | 959 if (value.isEmpty() || |
| 948 !value.startsWith(argument, TextCaseASCIIInsensitive)) | 960 !value.startsWith(argument, TextCaseASCIIInsensitive)) |
| 949 break; | 961 break; |
| 950 if (value.length() != argument.length() && | 962 if (value.length() != argument.length() && |
| 951 value[argument.length()] != '-') | 963 value[argument.length()] != '-') |
| 952 break; | 964 break; |
| 953 return true; | 965 return true; |
| 954 } | 966 } |
| 955 case CSSSelector::PseudoFullScreen: | 967 case CSSSelector::PseudoFullScreen: |
| 956 // While a Document is in the fullscreen state, and the document's current
fullscreen | 968 // While a Document is in the fullscreen state, and the document's current |
| 957 // element is an element in the document, the 'full-screen' pseudoclass ap
plies to | 969 // fullscreen element is an element in the document, the 'full-screen' |
| 958 // that element. Also, an <iframe>, <object> or <embed> element whose chil
d browsing | 970 // pseudoclass applies to that element. Also, an <iframe>, <object> or |
| 959 // context's Document is in the fullscreen state has the 'full-screen' pse
udoclass applied. | 971 // <embed> element whose child browsing context's Document is in the |
| 972 // fullscreen state has the 'full-screen' pseudoclass applied. |
| 960 if (isHTMLFrameElementBase(element) && | 973 if (isHTMLFrameElementBase(element) && |
| 961 element.containsFullScreenElement()) | 974 element.containsFullScreenElement()) |
| 962 return true; | 975 return true; |
| 963 return Fullscreen::isCurrentFullScreenElement(element); | 976 return Fullscreen::isCurrentFullScreenElement(element); |
| 964 case CSSSelector::PseudoFullScreenAncestor: | 977 case CSSSelector::PseudoFullScreenAncestor: |
| 965 return element.containsFullScreenElement(); | 978 return element.containsFullScreenElement(); |
| 966 case CSSSelector::PseudoInRange: | 979 case CSSSelector::PseudoInRange: |
| 967 if (m_mode == ResolvingStyle) | 980 if (m_mode == ResolvingStyle) |
| 968 element.document().setContainsValidityStyleRules(); | 981 element.document().setContainsValidityStyleRules(); |
| 969 return element.isInRange(); | 982 return element.isInRange(); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1013 case CSSSelector::PseudoIncrement: | 1026 case CSSSelector::PseudoIncrement: |
| 1014 case CSSSelector::PseudoStart: | 1027 case CSSSelector::PseudoStart: |
| 1015 case CSSSelector::PseudoEnd: | 1028 case CSSSelector::PseudoEnd: |
| 1016 case CSSSelector::PseudoDoubleButton: | 1029 case CSSSelector::PseudoDoubleButton: |
| 1017 case CSSSelector::PseudoSingleButton: | 1030 case CSSSelector::PseudoSingleButton: |
| 1018 case CSSSelector::PseudoNoButton: | 1031 case CSSSelector::PseudoNoButton: |
| 1019 case CSSSelector::PseudoCornerPresent: | 1032 case CSSSelector::PseudoCornerPresent: |
| 1020 return false; | 1033 return false; |
| 1021 case CSSSelector::PseudoUnknown: | 1034 case CSSSelector::PseudoUnknown: |
| 1022 default: | 1035 default: |
| 1023 ASSERT_NOT_REACHED(); | 1036 NOTREACHED(); |
| 1024 break; | 1037 break; |
| 1025 } | 1038 } |
| 1026 return false; | 1039 return false; |
| 1027 } | 1040 } |
| 1028 | 1041 |
| 1029 bool SelectorChecker::checkPseudoElement(const SelectorCheckingContext& context, | 1042 bool SelectorChecker::checkPseudoElement(const SelectorCheckingContext& context, |
| 1030 MatchResult& result) const { | 1043 MatchResult& result) const { |
| 1031 const CSSSelector& selector = *context.selector; | 1044 const CSSSelector& selector = *context.selector; |
| 1032 Element& element = *context.element; | 1045 Element& element = *context.element; |
| 1033 | 1046 |
| (...skipping 25 matching lines...) Expand all Loading... |
| 1059 return root->type() == ShadowRootType::UserAgent && | 1072 return root->type() == ShadowRootType::UserAgent && |
| 1060 element.shadowPseudoId() == selector.value(); | 1073 element.shadowPseudoId() == selector.value(); |
| 1061 return false; | 1074 return false; |
| 1062 case CSSSelector::PseudoSlotted: { | 1075 case CSSSelector::PseudoSlotted: { |
| 1063 SelectorCheckingContext subContext(context); | 1076 SelectorCheckingContext subContext(context); |
| 1064 subContext.isSubSelector = true; | 1077 subContext.isSubSelector = true; |
| 1065 subContext.scope = nullptr; | 1078 subContext.scope = nullptr; |
| 1066 subContext.treatShadowHostAsNormalScope = false; | 1079 subContext.treatShadowHostAsNormalScope = false; |
| 1067 | 1080 |
| 1068 // ::slotted() only allows one compound selector. | 1081 // ::slotted() only allows one compound selector. |
| 1069 ASSERT(selector.selectorList()->first()); | 1082 DCHECK(selector.selectorList()->first()); |
| 1070 ASSERT(!CSSSelectorList::next(*selector.selectorList()->first())); | 1083 DCHECK(!CSSSelectorList::next(*selector.selectorList()->first())); |
| 1071 subContext.selector = selector.selectorList()->first(); | 1084 subContext.selector = selector.selectorList()->first(); |
| 1072 return match(subContext); | 1085 return match(subContext); |
| 1073 } | 1086 } |
| 1074 case CSSSelector::PseudoContent: | 1087 case CSSSelector::PseudoContent: |
| 1075 return element.isInShadowTree() && element.isInsertionPoint(); | 1088 return element.isInShadowTree() && element.isInsertionPoint(); |
| 1076 case CSSSelector::PseudoShadow: | 1089 case CSSSelector::PseudoShadow: |
| 1077 return element.isInShadowTree() && context.previousElement; | 1090 return element.isInShadowTree() && context.previousElement; |
| 1078 default: | 1091 default: |
| 1079 if (m_mode == SharingRules) | 1092 if (m_mode == SharingRules) |
| 1080 return true; | 1093 return true; |
| 1081 ASSERT(m_mode != QueryingRules); | 1094 DCHECK_NE(m_mode, QueryingRules); |
| 1082 result.dynamicPseudo = CSSSelector::pseudoId(selector.getPseudoType()); | 1095 result.dynamicPseudo = CSSSelector::pseudoId(selector.getPseudoType()); |
| 1083 ASSERT(result.dynamicPseudo != PseudoIdNone); | 1096 DCHECK_NE(result.dynamicPseudo, PseudoIdNone); |
| 1084 return true; | 1097 return true; |
| 1085 } | 1098 } |
| 1086 } | 1099 } |
| 1087 | 1100 |
| 1088 bool SelectorChecker::checkPseudoHost(const SelectorCheckingContext& context, | 1101 bool SelectorChecker::checkPseudoHost(const SelectorCheckingContext& context, |
| 1089 MatchResult& result) const { | 1102 MatchResult& result) const { |
| 1090 const CSSSelector& selector = *context.selector; | 1103 const CSSSelector& selector = *context.selector; |
| 1091 Element& element = *context.element; | 1104 Element& element = *context.element; |
| 1092 | 1105 |
| 1093 if (m_mode == SharingRules) | 1106 if (m_mode == SharingRules) |
| 1094 return true; | 1107 return true; |
| 1095 // :host only matches a shadow host when :host is in a shadow tree of the shad
ow host. | 1108 // :host only matches a shadow host when :host is in a shadow tree of the |
| 1109 // shadow host. |
| 1096 if (!context.scope) | 1110 if (!context.scope) |
| 1097 return false; | 1111 return false; |
| 1098 const ContainerNode* shadowHost = context.scope->ownerShadowHost(); | 1112 const ContainerNode* shadowHost = context.scope->ownerShadowHost(); |
| 1099 if (!shadowHost || shadowHost != element) | 1113 if (!shadowHost || shadowHost != element) |
| 1100 return false; | 1114 return false; |
| 1101 ASSERT(element.shadow()); | 1115 DCHECK(element.shadow()); |
| 1102 | 1116 |
| 1103 // For the case with no parameters, i.e. just :host. | 1117 // For the case with no parameters, i.e. just :host. |
| 1104 if (!selector.selectorList()) | 1118 if (!selector.selectorList()) |
| 1105 return true; | 1119 return true; |
| 1106 | 1120 |
| 1107 SelectorCheckingContext subContext(context); | 1121 SelectorCheckingContext subContext(context); |
| 1108 subContext.isSubSelector = true; | 1122 subContext.isSubSelector = true; |
| 1109 | 1123 |
| 1110 bool matched = false; | 1124 bool matched = false; |
| 1111 unsigned maxSpecificity = 0; | 1125 unsigned maxSpecificity = 0; |
| 1112 | 1126 |
| 1113 // If one of simple selectors matches an element, returns SelectorMatches. Jus
t "OR". | 1127 // If one of simple selectors matches an element, returns SelectorMatches. |
| 1128 // Just "OR". |
| 1114 for (subContext.selector = selector.selectorList()->first(); | 1129 for (subContext.selector = selector.selectorList()->first(); |
| 1115 subContext.selector; | 1130 subContext.selector; |
| 1116 subContext.selector = CSSSelectorList::next(*subContext.selector)) { | 1131 subContext.selector = CSSSelectorList::next(*subContext.selector)) { |
| 1117 subContext.treatShadowHostAsNormalScope = true; | 1132 subContext.treatShadowHostAsNormalScope = true; |
| 1118 subContext.scope = context.scope; | 1133 subContext.scope = context.scope; |
| 1119 // Use FlatTreeTraversal to traverse a composed ancestor list of a given ele
ment. | 1134 // Use FlatTreeTraversal to traverse a composed ancestor list of a given |
| 1135 // element. |
| 1120 Element* nextElement = &element; | 1136 Element* nextElement = &element; |
| 1121 SelectorCheckingContext hostContext(subContext); | 1137 SelectorCheckingContext hostContext(subContext); |
| 1122 do { | 1138 do { |
| 1123 MatchResult subResult; | 1139 MatchResult subResult; |
| 1124 hostContext.element = nextElement; | 1140 hostContext.element = nextElement; |
| 1125 if (match(hostContext, subResult)) { | 1141 if (match(hostContext, subResult)) { |
| 1126 matched = true; | 1142 matched = true; |
| 1127 // Consider div:host(div:host(div:host(div:host...))). | 1143 // Consider div:host(div:host(div:host(div:host...))). |
| 1128 maxSpecificity = | 1144 maxSpecificity = |
| 1129 std::max(maxSpecificity, hostContext.selector->specificity() + | 1145 std::max(maxSpecificity, hostContext.selector->specificity() + |
| (...skipping 20 matching lines...) Expand all Loading... |
| 1150 } | 1166 } |
| 1151 | 1167 |
| 1152 bool SelectorChecker::checkScrollbarPseudoClass( | 1168 bool SelectorChecker::checkScrollbarPseudoClass( |
| 1153 const SelectorCheckingContext& context, | 1169 const SelectorCheckingContext& context, |
| 1154 MatchResult& result) const { | 1170 MatchResult& result) const { |
| 1155 const CSSSelector& selector = *context.selector; | 1171 const CSSSelector& selector = *context.selector; |
| 1156 | 1172 |
| 1157 if (selector.getPseudoType() == CSSSelector::PseudoNot) | 1173 if (selector.getPseudoType() == CSSSelector::PseudoNot) |
| 1158 return checkPseudoNot(context, result); | 1174 return checkPseudoNot(context, result); |
| 1159 | 1175 |
| 1160 // FIXME: This is a temporary hack for resizers and scrollbar corners. Eventua
lly :window-inactive should become a real | 1176 // FIXME: This is a temporary hack for resizers and scrollbar corners. |
| 1177 // Eventually :window-inactive should become a real |
| 1161 // pseudo class and just apply to everything. | 1178 // pseudo class and just apply to everything. |
| 1162 if (selector.getPseudoType() == CSSSelector::PseudoWindowInactive) | 1179 if (selector.getPseudoType() == CSSSelector::PseudoWindowInactive) |
| 1163 return !context.element->document().page()->focusController().isActive(); | 1180 return !context.element->document().page()->focusController().isActive(); |
| 1164 | 1181 |
| 1165 if (!m_scrollbar) | 1182 if (!m_scrollbar) |
| 1166 return false; | 1183 return false; |
| 1167 | 1184 |
| 1168 switch (selector.getPseudoType()) { | 1185 switch (selector.getPseudoType()) { |
| 1169 case CSSSelector::PseudoEnabled: | 1186 case CSSSelector::PseudoEnabled: |
| 1170 return m_scrollbar->enabled(); | 1187 return m_scrollbar->enabled(); |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1253 } | 1270 } |
| 1254 | 1271 |
| 1255 bool SelectorChecker::matchesFocusPseudoClass(const Element& element) { | 1272 bool SelectorChecker::matchesFocusPseudoClass(const Element& element) { |
| 1256 if (InspectorInstrumentation::forcePseudoState(const_cast<Element*>(&element), | 1273 if (InspectorInstrumentation::forcePseudoState(const_cast<Element*>(&element), |
| 1257 CSSSelector::PseudoFocus)) | 1274 CSSSelector::PseudoFocus)) |
| 1258 return true; | 1275 return true; |
| 1259 return element.isFocused() && isFrameFocused(element); | 1276 return element.isFocused() && isFrameFocused(element); |
| 1260 } | 1277 } |
| 1261 | 1278 |
| 1262 } // namespace blink | 1279 } // namespace blink |
| OLD | NEW |