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 |