| 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 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 57 | 57 |
| 58 using namespace HTMLNames; | 58 using namespace HTMLNames; |
| 59 | 59 |
| 60 SelectorChecker::SelectorChecker(Document& document, Mode mode) | 60 SelectorChecker::SelectorChecker(Document& document, Mode mode) |
| 61 : m_strictParsing(!document.inQuirksMode()) | 61 : m_strictParsing(!document.inQuirksMode()) |
| 62 , m_documentIsHTML(document.isHTMLDocument()) | 62 , m_documentIsHTML(document.isHTMLDocument()) |
| 63 , m_mode(mode) | 63 , m_mode(mode) |
| 64 { | 64 { |
| 65 } | 65 } |
| 66 | 66 |
| 67 static bool matchesCustomPseudoElement(const Element* element, const CSSSelector
* selector) | 67 static bool matchesCustomPseudoElement(const Element* element, const CSSSelector
& selector) |
| 68 { | 68 { |
| 69 ShadowRoot* root = element->containingShadowRoot(); | 69 ShadowRoot* root = element->containingShadowRoot(); |
| 70 if (!root || root->type() != ShadowRoot::UserAgentShadowRoot) | 70 if (!root || root->type() != ShadowRoot::UserAgentShadowRoot) |
| 71 return false; | 71 return false; |
| 72 | 72 |
| 73 if (element->shadowPseudoId() != selector->value()) | 73 if (element->shadowPseudoId() != selector.value()) |
| 74 return false; | 74 return false; |
| 75 | 75 |
| 76 return true; | 76 return true; |
| 77 } | 77 } |
| 78 | 78 |
| 79 Element* SelectorChecker::parentElement(const SelectorCheckingContext& context,
bool allowToCrossBoundary) const | 79 Element* SelectorChecker::parentElement(const SelectorCheckingContext& context,
bool allowToCrossBoundary) const |
| 80 { | 80 { |
| 81 // CrossesBoundary means we don't care any context.scope. So we can walk up
from a shadow root to its shadow host. | 81 // CrossesBoundary means we don't care any context.scope. So we can walk up
from a shadow root to its shadow host. |
| 82 if (allowToCrossBoundary) | 82 if (allowToCrossBoundary) |
| 83 return context.element->parentOrShadowHostElement(); | 83 return context.element->parentOrShadowHostElement(); |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 126 template<typename SiblingTraversalStrategy> | 126 template<typename SiblingTraversalStrategy> |
| 127 SelectorChecker::Match SelectorChecker::match(const SelectorCheckingContext& con
text, const SiblingTraversalStrategy& siblingTraversalStrategy, MatchResult* res
ult) const | 127 SelectorChecker::Match SelectorChecker::match(const SelectorCheckingContext& con
text, const SiblingTraversalStrategy& siblingTraversalStrategy, MatchResult* res
ult) const |
| 128 { | 128 { |
| 129 // first selector has to match | 129 // first selector has to match |
| 130 unsigned specificity = 0; | 130 unsigned specificity = 0; |
| 131 if (!checkOne(context, siblingTraversalStrategy, &specificity)) | 131 if (!checkOne(context, siblingTraversalStrategy, &specificity)) |
| 132 return SelectorFailsLocally; | 132 return SelectorFailsLocally; |
| 133 | 133 |
| 134 if (context.selector->m_match == CSSSelector::PseudoElement) { | 134 if (context.selector->m_match == CSSSelector::PseudoElement) { |
| 135 if (context.selector->isCustomPseudoElement()) { | 135 if (context.selector->isCustomPseudoElement()) { |
| 136 if (!matchesCustomPseudoElement(context.element, context.selector)) | 136 if (!matchesCustomPseudoElement(context.element, *context.selector)) |
| 137 return SelectorFailsLocally; | 137 return SelectorFailsLocally; |
| 138 } else if (context.selector->isContentPseudoElement()) { | 138 } else if (context.selector->isContentPseudoElement()) { |
| 139 if (!context.element->isInShadowTree() || !context.element->isInsert
ionPoint()) | 139 if (!context.element->isInShadowTree() || !context.element->isInsert
ionPoint()) |
| 140 return SelectorFailsLocally; | 140 return SelectorFailsLocally; |
| 141 } else { | 141 } else { |
| 142 if ((!context.elementStyle && m_mode == ResolvingStyle) || m_mode ==
QueryingRules) | 142 if ((!context.elementStyle && m_mode == ResolvingStyle) || m_mode ==
QueryingRules) |
| 143 return SelectorFailsLocally; | 143 return SelectorFailsLocally; |
| 144 | 144 |
| 145 PseudoId pseudoId = CSSSelector::pseudoId(context.selector->pseudoTy
pe()); | 145 PseudoId pseudoId = CSSSelector::pseudoId(context.selector->pseudoTy
pe()); |
| 146 if (pseudoId == FIRST_LETTER) | 146 if (pseudoId == FIRST_LETTER) |
| (...skipping 313 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 460 } | 460 } |
| 461 | 461 |
| 462 return false; | 462 return false; |
| 463 } | 463 } |
| 464 | 464 |
| 465 template<typename SiblingTraversalStrategy> | 465 template<typename SiblingTraversalStrategy> |
| 466 bool SelectorChecker::checkOne(const SelectorCheckingContext& context, const Sib
lingTraversalStrategy& siblingTraversalStrategy, unsigned* specificity) const | 466 bool SelectorChecker::checkOne(const SelectorCheckingContext& context, const Sib
lingTraversalStrategy& siblingTraversalStrategy, unsigned* specificity) const |
| 467 { | 467 { |
| 468 ASSERT(context.element); | 468 ASSERT(context.element); |
| 469 Element& element = *context.element; | 469 Element& element = *context.element; |
| 470 const CSSSelector* const & selector = context.selector; | 470 ASSERT(context.selector); |
| 471 ASSERT(selector); | 471 const CSSSelector& selector = *context.selector; |
| 472 |
| 472 bool elementIsHostInItsShadowTree = isHostInItsShadowTree(element, context.b
ehaviorAtBoundary, context.scope); | 473 bool elementIsHostInItsShadowTree = isHostInItsShadowTree(element, context.b
ehaviorAtBoundary, context.scope); |
| 473 | 474 |
| 474 if (selector->m_match == CSSSelector::Tag) | 475 if (selector.m_match == CSSSelector::Tag) |
| 475 return SelectorChecker::tagMatches(element, selector->tagQName(), elemen
tIsHostInItsShadowTree ? MatchingHostInItsShadowTree : MatchingElement); | 476 return SelectorChecker::tagMatches(element, selector.tagQName(), element
IsHostInItsShadowTree ? MatchingHostInItsShadowTree : MatchingElement); |
| 476 | 477 |
| 477 if (selector->m_match == CSSSelector::Class) | 478 if (selector.m_match == CSSSelector::Class) |
| 478 return element.hasClass() && element.classNames().contains(selector->val
ue()) && !elementIsHostInItsShadowTree; | 479 return element.hasClass() && element.classNames().contains(selector.valu
e()) && !elementIsHostInItsShadowTree; |
| 479 | 480 |
| 480 if (selector->m_match == CSSSelector::Id) | 481 if (selector.m_match == CSSSelector::Id) |
| 481 return element.hasID() && element.idForStyleResolution() == selector->va
lue() && !elementIsHostInItsShadowTree; | 482 return element.hasID() && element.idForStyleResolution() == selector.val
ue() && !elementIsHostInItsShadowTree; |
| 482 | 483 |
| 483 if (selector->isAttributeSelector()) { | 484 if (selector.isAttributeSelector()) { |
| 484 if (elementIsHostInItsShadowTree) | 485 if (elementIsHostInItsShadowTree) |
| 485 return false; | 486 return false; |
| 486 if (!anyAttributeMatches(element, static_cast<CSSSelector::Match>(select
or->m_match), *selector)) | 487 if (!anyAttributeMatches(element, static_cast<CSSSelector::Match>(select
or.m_match), selector)) |
| 487 return false; | 488 return false; |
| 488 } | 489 } |
| 489 | 490 |
| 490 if (selector->m_match == CSSSelector::PseudoClass) { | 491 if (selector.m_match == CSSSelector::PseudoClass) { |
| 491 // Handle :not up front. | 492 // Handle :not up front. |
| 492 if (selector->pseudoType() == CSSSelector::PseudoNot) { | 493 if (selector.pseudoType() == CSSSelector::PseudoNot) { |
| 493 SelectorCheckingContext subContext(context); | 494 SelectorCheckingContext subContext(context); |
| 494 subContext.isSubSelector = true; | 495 subContext.isSubSelector = true; |
| 495 ASSERT(selector->selectorList()); | 496 ASSERT(selector.selectorList()); |
| 496 for (subContext.selector = selector->selectorList()->first(); subCon
text.selector; subContext.selector = subContext.selector->tagHistory()) { | 497 for (subContext.selector = selector.selectorList()->first(); subCont
ext.selector; subContext.selector = subContext.selector->tagHistory()) { |
| 497 // :not cannot nest. I don't really know why this is a | 498 // :not cannot nest. I don't really know why this is a |
| 498 // restriction in CSS3, but it is, so let's honor it. | 499 // restriction in CSS3, but it is, so let's honor it. |
| 499 // the parser enforces that this never occurs | 500 // the parser enforces that this never occurs |
| 500 ASSERT(subContext.selector->pseudoType() != CSSSelector::PseudoN
ot); | 501 ASSERT(subContext.selector->pseudoType() != CSSSelector::PseudoN
ot); |
| 501 // We select between :visited and :link when applying. We don't
know which one applied (or not) yet. | 502 // We select between :visited and :link when applying. We don't
know which one applied (or not) yet. |
| 502 if (subContext.selector->pseudoType() == CSSSelector::PseudoVisi
ted || (subContext.selector->pseudoType() == CSSSelector::PseudoLink && subConte
xt.visitedMatchType == VisitedMatchEnabled)) | 503 if (subContext.selector->pseudoType() == CSSSelector::PseudoVisi
ted || (subContext.selector->pseudoType() == CSSSelector::PseudoLink && subConte
xt.visitedMatchType == VisitedMatchEnabled)) |
| 503 return true; | 504 return true; |
| 504 if (!checkOne(subContext, DOMSiblingTraversalStrategy())) | 505 if (!checkOne(subContext, DOMSiblingTraversalStrategy())) |
| 505 return true; | 506 return true; |
| 506 } | 507 } |
| 507 } else if (context.hasScrollbarPseudo) { | 508 } else if (context.hasScrollbarPseudo) { |
| 508 // CSS scrollbars match a specific subset of pseudo classes, and the
y have specialized rules for each | 509 // CSS scrollbars match a specific subset of pseudo classes, and the
y have specialized rules for each |
| 509 // (since there are no elements involved). | 510 // (since there are no elements involved). |
| 510 return checkScrollbarPseudoClass(context, &element.document(), selec
tor); | 511 return checkScrollbarPseudoClass(context, &element.document(), selec
tor); |
| 511 } else if (context.hasSelectionPseudo) { | 512 } else if (context.hasSelectionPseudo) { |
| 512 if (selector->pseudoType() == CSSSelector::PseudoWindowInactive) | 513 if (selector.pseudoType() == CSSSelector::PseudoWindowInactive) |
| 513 return !element.document().page()->focusController().isActive(); | 514 return !element.document().page()->focusController().isActive(); |
| 514 } | 515 } |
| 515 | 516 |
| 516 // Normal element pseudo class checking. | 517 // Normal element pseudo class checking. |
| 517 switch (selector->pseudoType()) { | 518 switch (selector.pseudoType()) { |
| 518 // Pseudo classes: | 519 // Pseudo classes: |
| 519 case CSSSelector::PseudoNot: | 520 case CSSSelector::PseudoNot: |
| 520 break; // Already handled up above. | 521 break; // Already handled up above. |
| 521 case CSSSelector::PseudoEmpty: | 522 case CSSSelector::PseudoEmpty: |
| 522 { | 523 { |
| 523 bool result = true; | 524 bool result = true; |
| 524 for (Node* n = element.firstChild(); n; n = n->nextSibling()) { | 525 for (Node* n = element.firstChild(); n; n = n->nextSibling()) { |
| 525 if (n->isElementNode()) { | 526 if (n->isElementNode()) { |
| 526 result = false; | 527 result = false; |
| 527 break; | 528 break; |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 610 if (m_mode == ResolvingStyle) { | 611 if (m_mode == ResolvingStyle) { |
| 611 parent->setChildrenAffectedByForwardPositionalRules(); | 612 parent->setChildrenAffectedByForwardPositionalRules(); |
| 612 parent->setChildrenAffectedByBackwardPositionalRules(); | 613 parent->setChildrenAffectedByBackwardPositionalRules(); |
| 613 } | 614 } |
| 614 if (!parent->isFinishedParsingChildren()) | 615 if (!parent->isFinishedParsingChildren()) |
| 615 return false; | 616 return false; |
| 616 return siblingTraversalStrategy.isFirstOfType(&element, element.
tagQName()) && siblingTraversalStrategy.isLastOfType(&element, element.tagQName(
)); | 617 return siblingTraversalStrategy.isFirstOfType(&element, element.
tagQName()) && siblingTraversalStrategy.isLastOfType(&element, element.tagQName(
)); |
| 617 } | 618 } |
| 618 break; | 619 break; |
| 619 case CSSSelector::PseudoNthChild: | 620 case CSSSelector::PseudoNthChild: |
| 620 if (!selector->parseNth()) | 621 if (!selector.parseNth()) |
| 621 break; | 622 break; |
| 622 if (Element* parent = element.parentElement()) { | 623 if (Element* parent = element.parentElement()) { |
| 623 int count = 1 + siblingTraversalStrategy.countElementsBefore(&el
ement); | 624 int count = 1 + siblingTraversalStrategy.countElementsBefore(&el
ement); |
| 624 if (m_mode == ResolvingStyle) { | 625 if (m_mode == ResolvingStyle) { |
| 625 RenderStyle* childStyle = context.elementStyle ? context.ele
mentStyle : element.renderStyle(); | 626 RenderStyle* childStyle = context.elementStyle ? context.ele
mentStyle : element.renderStyle(); |
| 626 element.setChildIndex(count); | 627 element.setChildIndex(count); |
| 627 if (childStyle) | 628 if (childStyle) |
| 628 childStyle->setUnique(); | 629 childStyle->setUnique(); |
| 629 parent->setChildrenAffectedByForwardPositionalRules(); | 630 parent->setChildrenAffectedByForwardPositionalRules(); |
| 630 } | 631 } |
| 631 | 632 |
| 632 if (selector->matchNth(count)) | 633 if (selector.matchNth(count)) |
| 633 return true; | 634 return true; |
| 634 } | 635 } |
| 635 break; | 636 break; |
| 636 case CSSSelector::PseudoNthOfType: | 637 case CSSSelector::PseudoNthOfType: |
| 637 if (!selector->parseNth()) | 638 if (!selector.parseNth()) |
| 638 break; | 639 break; |
| 639 if (Element* parent = element.parentElement()) { | 640 if (Element* parent = element.parentElement()) { |
| 640 int count = 1 + siblingTraversalStrategy.countElementsOfTypeBefo
re(&element, element.tagQName()); | 641 int count = 1 + siblingTraversalStrategy.countElementsOfTypeBefo
re(&element, element.tagQName()); |
| 641 if (m_mode == ResolvingStyle) | 642 if (m_mode == ResolvingStyle) |
| 642 parent->setChildrenAffectedByForwardPositionalRules(); | 643 parent->setChildrenAffectedByForwardPositionalRules(); |
| 643 | 644 |
| 644 if (selector->matchNth(count)) | 645 if (selector.matchNth(count)) |
| 645 return true; | 646 return true; |
| 646 } | 647 } |
| 647 break; | 648 break; |
| 648 case CSSSelector::PseudoNthLastChild: | 649 case CSSSelector::PseudoNthLastChild: |
| 649 if (!selector->parseNth()) | 650 if (!selector.parseNth()) |
| 650 break; | 651 break; |
| 651 if (Element* parent = element.parentElement()) { | 652 if (Element* parent = element.parentElement()) { |
| 652 if (m_mode == ResolvingStyle) | 653 if (m_mode == ResolvingStyle) |
| 653 parent->setChildrenAffectedByBackwardPositionalRules(); | 654 parent->setChildrenAffectedByBackwardPositionalRules(); |
| 654 if (!parent->isFinishedParsingChildren()) | 655 if (!parent->isFinishedParsingChildren()) |
| 655 return false; | 656 return false; |
| 656 int count = 1 + siblingTraversalStrategy.countElementsAfter(&ele
ment); | 657 int count = 1 + siblingTraversalStrategy.countElementsAfter(&ele
ment); |
| 657 if (selector->matchNth(count)) | 658 if (selector.matchNth(count)) |
| 658 return true; | 659 return true; |
| 659 } | 660 } |
| 660 break; | 661 break; |
| 661 case CSSSelector::PseudoNthLastOfType: | 662 case CSSSelector::PseudoNthLastOfType: |
| 662 if (!selector->parseNth()) | 663 if (!selector.parseNth()) |
| 663 break; | 664 break; |
| 664 if (Element* parent = element.parentElement()) { | 665 if (Element* parent = element.parentElement()) { |
| 665 if (m_mode == ResolvingStyle) | 666 if (m_mode == ResolvingStyle) |
| 666 parent->setChildrenAffectedByBackwardPositionalRules(); | 667 parent->setChildrenAffectedByBackwardPositionalRules(); |
| 667 if (!parent->isFinishedParsingChildren()) | 668 if (!parent->isFinishedParsingChildren()) |
| 668 return false; | 669 return false; |
| 669 | 670 |
| 670 int count = 1 + siblingTraversalStrategy.countElementsOfTypeAfte
r(&element, element.tagQName()); | 671 int count = 1 + siblingTraversalStrategy.countElementsOfTypeAfte
r(&element, element.tagQName()); |
| 671 if (selector->matchNth(count)) | 672 if (selector.matchNth(count)) |
| 672 return true; | 673 return true; |
| 673 } | 674 } |
| 674 break; | 675 break; |
| 675 case CSSSelector::PseudoTarget: | 676 case CSSSelector::PseudoTarget: |
| 676 if (element == element.document().cssTarget()) | 677 if (element == element.document().cssTarget()) |
| 677 return true; | 678 return true; |
| 678 break; | 679 break; |
| 679 case CSSSelector::PseudoAny: | 680 case CSSSelector::PseudoAny: |
| 680 { | 681 { |
| 681 SelectorCheckingContext subContext(context); | 682 SelectorCheckingContext subContext(context); |
| 682 subContext.isSubSelector = true; | 683 subContext.isSubSelector = true; |
| 683 ASSERT(selector->selectorList()); | 684 ASSERT(selector.selectorList()); |
| 684 for (subContext.selector = selector->selectorList()->first(); su
bContext.selector; subContext.selector = CSSSelectorList::next(subContext.select
or)) { | 685 for (subContext.selector = selector.selectorList()->first(); sub
Context.selector; subContext.selector = CSSSelectorList::next(*subContext.select
or)) { |
| 685 if (match(subContext, siblingTraversalStrategy) == SelectorM
atches) | 686 if (match(subContext, siblingTraversalStrategy) == SelectorM
atches) |
| 686 return true; | 687 return true; |
| 687 } | 688 } |
| 688 } | 689 } |
| 689 break; | 690 break; |
| 690 case CSSSelector::PseudoAutofill: | 691 case CSSSelector::PseudoAutofill: |
| 691 if (!element.isFormControlElement()) | 692 if (!element.isFormControlElement()) |
| 692 break; | 693 break; |
| 693 return toHTMLFormControlElement(element).isAutofilled(); | 694 return toHTMLFormControlElement(element).isAutofilled(); |
| 694 case CSSSelector::PseudoAnyLink: | 695 case CSSSelector::PseudoAnyLink: |
| (...skipping 17 matching lines...) Expand all Loading... |
| 712 if (m_mode == ResolvingStyle) { | 713 if (m_mode == ResolvingStyle) { |
| 713 if (context.elementStyle) | 714 if (context.elementStyle) |
| 714 context.elementStyle->setAffectedByFocus(); | 715 context.elementStyle->setAffectedByFocus(); |
| 715 else | 716 else |
| 716 element.setChildrenAffectedByFocus(); | 717 element.setChildrenAffectedByFocus(); |
| 717 } | 718 } |
| 718 return matchesFocusPseudoClass(element); | 719 return matchesFocusPseudoClass(element); |
| 719 case CSSSelector::PseudoHover: | 720 case CSSSelector::PseudoHover: |
| 720 // If we're in quirks mode, then hover should never match anchors wi
th no | 721 // If we're in quirks mode, then hover should never match anchors wi
th no |
| 721 // href and *:hover should not match anything. This is important for
sites like wsj.com. | 722 // href and *:hover should not match anything. This is important for
sites like wsj.com. |
| 722 if (m_strictParsing || context.isSubSelector || (selector->m_match =
= CSSSelector::Tag && selector->tagQName() != anyQName() && !element.hasTagName(
aTag)) || element.isLink()) { | 723 if (m_strictParsing || context.isSubSelector || (selector.m_match ==
CSSSelector::Tag && selector.tagQName() != anyQName() && !element.hasTagName(aT
ag)) || element.isLink()) { |
| 723 if (m_mode == ResolvingStyle) { | 724 if (m_mode == ResolvingStyle) { |
| 724 if (context.elementStyle) | 725 if (context.elementStyle) |
| 725 context.elementStyle->setAffectedByHover(); | 726 context.elementStyle->setAffectedByHover(); |
| 726 else | 727 else |
| 727 element.setChildrenAffectedByHover(); | 728 element.setChildrenAffectedByHover(); |
| 728 } | 729 } |
| 729 if (element.hovered() || InspectorInstrumentation::forcePseudoSt
ate(&element, CSSSelector::PseudoHover)) | 730 if (element.hovered() || InspectorInstrumentation::forcePseudoSt
ate(&element, CSSSelector::PseudoHover)) |
| 730 return true; | 731 return true; |
| 731 } | 732 } |
| 732 break; | 733 break; |
| 733 case CSSSelector::PseudoActive: | 734 case CSSSelector::PseudoActive: |
| 734 // If we're in quirks mode, then :active should never match anchors
with no | 735 // If we're in quirks mode, then :active should never match anchors
with no |
| 735 // href and *:active should not match anything. | 736 // href and *:active should not match anything. |
| 736 if (m_strictParsing || context.isSubSelector || (selector->m_match =
= CSSSelector::Tag && selector->tagQName() != anyQName() && !element.hasTagName(
aTag)) || element.isLink()) { | 737 if (m_strictParsing || context.isSubSelector || (selector.m_match ==
CSSSelector::Tag && selector.tagQName() != anyQName() && !element.hasTagName(aT
ag)) || element.isLink()) { |
| 737 if (m_mode == ResolvingStyle) { | 738 if (m_mode == ResolvingStyle) { |
| 738 if (context.elementStyle) | 739 if (context.elementStyle) |
| 739 context.elementStyle->setAffectedByActive(); | 740 context.elementStyle->setAffectedByActive(); |
| 740 else | 741 else |
| 741 element.setChildrenAffectedByActive(); | 742 element.setChildrenAffectedByActive(); |
| 742 } | 743 } |
| 743 if (element.active() || InspectorInstrumentation::forcePseudoSta
te(&element, CSSSelector::PseudoActive)) | 744 if (element.active() || InspectorInstrumentation::forcePseudoSta
te(&element, CSSSelector::PseudoActive)) |
| 744 return true; | 745 return true; |
| 745 } | 746 } |
| 746 break; | 747 break; |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 792 if (element == element.document().documentElement()) | 793 if (element == element.document().documentElement()) |
| 793 return true; | 794 return true; |
| 794 break; | 795 break; |
| 795 case CSSSelector::PseudoLang: | 796 case CSSSelector::PseudoLang: |
| 796 { | 797 { |
| 797 AtomicString value; | 798 AtomicString value; |
| 798 if (element.isVTTElement()) | 799 if (element.isVTTElement()) |
| 799 value = toVTTElement(element).language(); | 800 value = toVTTElement(element).language(); |
| 800 else | 801 else |
| 801 value = element.computeInheritedLanguage(); | 802 value = element.computeInheritedLanguage(); |
| 802 const AtomicString& argument = selector->argument(); | 803 const AtomicString& argument = selector.argument(); |
| 803 if (value.isEmpty() || !value.startsWith(argument, false)) | 804 if (value.isEmpty() || !value.startsWith(argument, false)) |
| 804 break; | 805 break; |
| 805 if (value.length() != argument.length() && value[argument.length
()] != '-') | 806 if (value.length() != argument.length() && value[argument.length
()] != '-') |
| 806 break; | 807 break; |
| 807 return true; | 808 return true; |
| 808 } | 809 } |
| 809 case CSSSelector::PseudoFullScreen: | 810 case CSSSelector::PseudoFullScreen: |
| 810 // While a Document is in the fullscreen state, and the document's c
urrent fullscreen | 811 // While a Document is in the fullscreen state, and the document's c
urrent fullscreen |
| 811 // element is an element in the document, the 'full-screen' pseudocl
ass applies to | 812 // element is an element in the document, the 'full-screen' pseudocl
ass applies to |
| 812 // that element. Also, an <iframe>, <object> or <embed> element whos
e child browsing | 813 // that element. Also, an <iframe>, <object> or <embed> element whos
e child browsing |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 853 | 854 |
| 854 case CSSSelector::PseudoHost: | 855 case CSSSelector::PseudoHost: |
| 855 case CSSSelector::PseudoAncestor: | 856 case CSSSelector::PseudoAncestor: |
| 856 { | 857 { |
| 857 // :host only matches a shadow host when :host is in a shadow tr
ee of the shadow host. | 858 // :host only matches a shadow host when :host is in a shadow tr
ee of the shadow host. |
| 858 if (!context.scope || !(context.behaviorAtBoundary & ScopeIsShad
owHost) || context.scope != element) | 859 if (!context.scope || !(context.behaviorAtBoundary & ScopeIsShad
owHost) || context.scope != element) |
| 859 return false; | 860 return false; |
| 860 ASSERT(element.shadow()); | 861 ASSERT(element.shadow()); |
| 861 | 862 |
| 862 // For empty parameter case, i.e. just :host or :host(). | 863 // For empty parameter case, i.e. just :host or :host(). |
| 863 if (!selector->selectorList()) // Use *'s specificity. So just 0
. | 864 if (!selector.selectorList()) // Use *'s specificity. So just 0. |
| 864 return true; | 865 return true; |
| 865 | 866 |
| 866 SelectorCheckingContext subContext(context); | 867 SelectorCheckingContext subContext(context); |
| 867 subContext.isSubSelector = true; | 868 subContext.isSubSelector = true; |
| 868 | 869 |
| 869 bool matched = false; | 870 bool matched = false; |
| 870 unsigned maxSpecificity = 0; | 871 unsigned maxSpecificity = 0; |
| 871 | 872 |
| 872 // If one of simple selectors matches an element, returns Select
orMatches. Just "OR". | 873 // If one of simple selectors matches an element, returns Select
orMatches. Just "OR". |
| 873 for (subContext.selector = selector->selectorList()->first(); su
bContext.selector; subContext.selector = CSSSelectorList::next(subContext.select
or)) { | 874 for (subContext.selector = selector.selectorList()->first(); sub
Context.selector; subContext.selector = CSSSelectorList::next(*subContext.select
or)) { |
| 874 subContext.behaviorAtBoundary = ScopeIsShadowHostInPseudoHos
tParameter; | 875 subContext.behaviorAtBoundary = ScopeIsShadowHostInPseudoHos
tParameter; |
| 875 subContext.scope = context.scope; | 876 subContext.scope = context.scope; |
| 876 // Use NodeRenderingTraversal to traverse a composed ancesto
r list of a given element. | 877 // Use NodeRenderingTraversal to traverse a composed ancesto
r list of a given element. |
| 877 Element* nextElement = &element; | 878 Element* nextElement = &element; |
| 878 do { | 879 do { |
| 879 MatchResult subResult; | 880 MatchResult subResult; |
| 880 subContext.element = nextElement; | 881 subContext.element = nextElement; |
| 881 if (match(subContext, siblingTraversalStrategy, &subResu
lt) == SelectorMatches) { | 882 if (match(subContext, siblingTraversalStrategy, &subResu
lt) == SelectorMatches) { |
| 882 matched = true; | 883 matched = true; |
| 883 // Consider div:host(div:host(div:host(div:host...))
). | 884 // Consider div:host(div:host(div:host(div:host...))
). |
| 884 maxSpecificity = std::max(maxSpecificity, subContext
.selector->specificity() + subResult.specificity); | 885 maxSpecificity = std::max(maxSpecificity, subContext
.selector->specificity() + subResult.specificity); |
| 885 break; | 886 break; |
| 886 } | 887 } |
| 887 subContext.behaviorAtBoundary = DoesNotCrossBoundary; | 888 subContext.behaviorAtBoundary = DoesNotCrossBoundary; |
| 888 subContext.scope = 0; | 889 subContext.scope = 0; |
| 889 | 890 |
| 890 if (selector->pseudoType() == CSSSelector::PseudoHost) | 891 if (selector.pseudoType() == CSSSelector::PseudoHost) |
| 891 break; | 892 break; |
| 892 | 893 |
| 893 nextElement = NodeRenderingTraversal::parentElement(next
Element); | 894 nextElement = NodeRenderingTraversal::parentElement(next
Element); |
| 894 } while (nextElement); | 895 } while (nextElement); |
| 895 } | 896 } |
| 896 if (matched) { | 897 if (matched) { |
| 897 if (specificity) | 898 if (specificity) |
| 898 *specificity = maxSpecificity; | 899 *specificity = maxSpecificity; |
| 899 return true; | 900 return true; |
| 900 } | 901 } |
| (...skipping 12 matching lines...) Expand all Loading... |
| 913 case CSSSelector::PseudoCornerPresent: | 914 case CSSSelector::PseudoCornerPresent: |
| 914 return false; | 915 return false; |
| 915 | 916 |
| 916 case CSSSelector::PseudoUnknown: | 917 case CSSSelector::PseudoUnknown: |
| 917 case CSSSelector::PseudoNotParsed: | 918 case CSSSelector::PseudoNotParsed: |
| 918 default: | 919 default: |
| 919 ASSERT_NOT_REACHED(); | 920 ASSERT_NOT_REACHED(); |
| 920 break; | 921 break; |
| 921 } | 922 } |
| 922 return false; | 923 return false; |
| 923 } | 924 } else if (selector.m_match == CSSSelector::PseudoElement && selector.pseudo
Type() == CSSSelector::PseudoCue) { |
| 924 else if (selector->m_match == CSSSelector::PseudoElement && selector->pseudo
Type() == CSSSelector::PseudoCue) { | |
| 925 SelectorCheckingContext subContext(context); | 925 SelectorCheckingContext subContext(context); |
| 926 subContext.isSubSelector = true; | 926 subContext.isSubSelector = true; |
| 927 subContext.behaviorAtBoundary = StaysWithinTreeScope; | 927 subContext.behaviorAtBoundary = StaysWithinTreeScope; |
| 928 | 928 |
| 929 const CSSSelector* const & selector = context.selector; | 929 const CSSSelector* contextSelector = context.selector; |
| 930 for (subContext.selector = selector->selectorList()->first(); subContext
.selector; subContext.selector = CSSSelectorList::next(subContext.selector)) { | 930 ASSERT(contextSelector); |
| 931 for (subContext.selector = contextSelector->selectorList()->first(); sub
Context.selector; subContext.selector = CSSSelectorList::next(*subContext.select
or)) { |
| 931 if (match(subContext, siblingTraversalStrategy) == SelectorMatches) | 932 if (match(subContext, siblingTraversalStrategy) == SelectorMatches) |
| 932 return true; | 933 return true; |
| 933 } | 934 } |
| 934 return false; | 935 return false; |
| 935 } | 936 } |
| 936 // ### add the rest of the checks... | 937 // ### add the rest of the checks... |
| 937 return true; | 938 return true; |
| 938 } | 939 } |
| 939 | 940 |
| 940 bool SelectorChecker::checkScrollbarPseudoClass(const SelectorCheckingContext& c
ontext, Document* document, const CSSSelector* selector) const | 941 bool SelectorChecker::checkScrollbarPseudoClass(const SelectorCheckingContext& c
ontext, Document* document, const CSSSelector& selector) const |
| 941 { | 942 { |
| 942 RenderScrollbar* scrollbar = context.scrollbar; | 943 RenderScrollbar* scrollbar = context.scrollbar; |
| 943 ScrollbarPart part = context.scrollbarPart; | 944 ScrollbarPart part = context.scrollbarPart; |
| 944 | 945 |
| 945 // FIXME: This is a temporary hack for resizers and scrollbar corners. Event
ually :window-inactive should become a real | 946 // FIXME: This is a temporary hack for resizers and scrollbar corners. Event
ually :window-inactive should become a real |
| 946 // pseudo class and just apply to everything. | 947 // pseudo class and just apply to everything. |
| 947 if (selector->pseudoType() == CSSSelector::PseudoWindowInactive) | 948 if (selector.pseudoType() == CSSSelector::PseudoWindowInactive) |
| 948 return !document->page()->focusController().isActive(); | 949 return !document->page()->focusController().isActive(); |
| 949 | 950 |
| 950 if (!scrollbar) | 951 if (!scrollbar) |
| 951 return false; | 952 return false; |
| 952 | 953 |
| 953 ASSERT(selector->m_match == CSSSelector::PseudoClass); | 954 ASSERT(selector.m_match == CSSSelector::PseudoClass); |
| 954 switch (selector->pseudoType()) { | 955 switch (selector.pseudoType()) { |
| 955 case CSSSelector::PseudoEnabled: | 956 case CSSSelector::PseudoEnabled: |
| 956 return scrollbar->enabled(); | 957 return scrollbar->enabled(); |
| 957 case CSSSelector::PseudoDisabled: | 958 case CSSSelector::PseudoDisabled: |
| 958 return !scrollbar->enabled(); | 959 return !scrollbar->enabled(); |
| 959 case CSSSelector::PseudoHover: | 960 case CSSSelector::PseudoHover: |
| 960 { | 961 { |
| 961 ScrollbarPart hoveredPart = scrollbar->hoveredPart(); | 962 ScrollbarPart hoveredPart = scrollbar->hoveredPart(); |
| 962 if (part == ScrollbarBGPart) | 963 if (part == ScrollbarBGPart) |
| 963 return hoveredPart != NoPart; | 964 return hoveredPart != NoPart; |
| 964 if (part == TrackBGPart) | 965 if (part == TrackBGPart) |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1011 return buttonsPlacement == ScrollbarButtonsNone || buttonsPlacem
ent == ScrollbarButtonsDoubleStart; | 1012 return buttonsPlacement == ScrollbarButtonsNone || buttonsPlacem
ent == ScrollbarButtonsDoubleStart; |
| 1012 return false; | 1013 return false; |
| 1013 } | 1014 } |
| 1014 case CSSSelector::PseudoCornerPresent: | 1015 case CSSSelector::PseudoCornerPresent: |
| 1015 return scrollbar->scrollableArea()->isScrollCornerVisible(); | 1016 return scrollbar->scrollableArea()->isScrollCornerVisible(); |
| 1016 default: | 1017 default: |
| 1017 return false; | 1018 return false; |
| 1018 } | 1019 } |
| 1019 } | 1020 } |
| 1020 | 1021 |
| 1021 unsigned SelectorChecker::determineLinkMatchType(const CSSSelector* selector) | 1022 unsigned SelectorChecker::determineLinkMatchType(const CSSSelector& selector) |
| 1022 { | 1023 { |
| 1023 unsigned linkMatchType = MatchAll; | 1024 unsigned linkMatchType = MatchAll; |
| 1024 | 1025 |
| 1025 // Statically determine if this selector will match a link in visited, unvis
ited or any state, or never. | 1026 // Statically determine if this selector will match a link in visited, unvis
ited or any state, or never. |
| 1026 // :visited never matches other elements than the innermost link element. | 1027 // :visited never matches other elements than the innermost link element. |
| 1027 for (; selector; selector = selector->tagHistory()) { | 1028 for (const CSSSelector* current = &selector; current; current = current->tag
History()) { |
| 1028 switch (selector->pseudoType()) { | 1029 switch (current->pseudoType()) { |
| 1029 case CSSSelector::PseudoNot: | 1030 case CSSSelector::PseudoNot: |
| 1030 { | 1031 { |
| 1031 // :not(:visited) is equivalent to :link. Parser enforces that :
not can't nest. | 1032 // :not(:visited) is equivalent to :link. Parser enforces that :
not can't nest. |
| 1032 ASSERT(selector->selectorList()); | 1033 ASSERT(current->selectorList()); |
| 1033 for (const CSSSelector* subSelector = selector->selectorList()->
first(); subSelector; subSelector = subSelector->tagHistory()) { | 1034 for (const CSSSelector* subSelector = current->selectorList()->f
irst(); subSelector; subSelector = subSelector->tagHistory()) { |
| 1034 CSSSelector::PseudoType subType = subSelector->pseudoType(); | 1035 CSSSelector::PseudoType subType = subSelector->pseudoType(); |
| 1035 if (subType == CSSSelector::PseudoVisited) | 1036 if (subType == CSSSelector::PseudoVisited) |
| 1036 linkMatchType &= ~SelectorChecker::MatchVisited; | 1037 linkMatchType &= ~SelectorChecker::MatchVisited; |
| 1037 else if (subType == CSSSelector::PseudoLink) | 1038 else if (subType == CSSSelector::PseudoLink) |
| 1038 linkMatchType &= ~SelectorChecker::MatchLink; | 1039 linkMatchType &= ~SelectorChecker::MatchLink; |
| 1039 } | 1040 } |
| 1040 } | 1041 } |
| 1041 break; | 1042 break; |
| 1042 case CSSSelector::PseudoLink: | 1043 case CSSSelector::PseudoLink: |
| 1043 linkMatchType &= ~SelectorChecker::MatchVisited; | 1044 linkMatchType &= ~SelectorChecker::MatchVisited; |
| 1044 break; | 1045 break; |
| 1045 case CSSSelector::PseudoVisited: | 1046 case CSSSelector::PseudoVisited: |
| 1046 linkMatchType &= ~SelectorChecker::MatchLink; | 1047 linkMatchType &= ~SelectorChecker::MatchLink; |
| 1047 break; | 1048 break; |
| 1048 default: | 1049 default: |
| 1049 // We don't support :link and :visited inside :-webkit-any. | 1050 // We don't support :link and :visited inside :-webkit-any. |
| 1050 break; | 1051 break; |
| 1051 } | 1052 } |
| 1052 CSSSelector::Relation relation = selector->relation(); | 1053 CSSSelector::Relation relation = current->relation(); |
| 1053 if (relation == CSSSelector::SubSelector) | 1054 if (relation == CSSSelector::SubSelector) |
| 1054 continue; | 1055 continue; |
| 1055 if (relation != CSSSelector::Descendant && relation != CSSSelector::Chil
d) | 1056 if (relation != CSSSelector::Descendant && relation != CSSSelector::Chil
d) |
| 1056 return linkMatchType; | 1057 return linkMatchType; |
| 1057 if (linkMatchType != MatchAll) | 1058 if (linkMatchType != MatchAll) |
| 1058 return linkMatchType; | 1059 return linkMatchType; |
| 1059 } | 1060 } |
| 1060 return linkMatchType; | 1061 return linkMatchType; |
| 1061 } | 1062 } |
| 1062 | 1063 |
| 1063 bool SelectorChecker::isFrameFocused(const Element& element) | 1064 bool SelectorChecker::isFrameFocused(const Element& element) |
| 1064 { | 1065 { |
| 1065 return element.document().frame() && element.document().frame()->selection()
.isFocusedAndActive(); | 1066 return element.document().frame() && element.document().frame()->selection()
.isFocusedAndActive(); |
| 1066 } | 1067 } |
| 1067 | 1068 |
| 1068 bool SelectorChecker::matchesFocusPseudoClass(const Element& element) | 1069 bool SelectorChecker::matchesFocusPseudoClass(const Element& element) |
| 1069 { | 1070 { |
| 1070 if (InspectorInstrumentation::forcePseudoState(const_cast<Element*>(&element
), CSSSelector::PseudoFocus)) | 1071 if (InspectorInstrumentation::forcePseudoState(const_cast<Element*>(&element
), CSSSelector::PseudoFocus)) |
| 1071 return true; | 1072 return true; |
| 1072 return element.focused() && isFrameFocused(element); | 1073 return element.focused() && isFrameFocused(element); |
| 1073 } | 1074 } |
| 1074 | 1075 |
| 1075 template | 1076 template |
| 1076 SelectorChecker::Match SelectorChecker::match(const SelectorCheckingContext&, co
nst DOMSiblingTraversalStrategy&, MatchResult*) const; | 1077 SelectorChecker::Match SelectorChecker::match(const SelectorCheckingContext&, co
nst DOMSiblingTraversalStrategy&, MatchResult*) const; |
| 1077 | 1078 |
| 1078 template | 1079 template |
| 1079 SelectorChecker::Match SelectorChecker::match(const SelectorCheckingContext&, co
nst ShadowDOMSiblingTraversalStrategy&, MatchResult*) const; | 1080 SelectorChecker::Match SelectorChecker::match(const SelectorCheckingContext&, co
nst ShadowDOMSiblingTraversalStrategy&, MatchResult*) const; |
| 1080 | 1081 |
| 1081 } | 1082 } |
| OLD | NEW |