Changeset 107197 in webkit
- Timestamp:
- Feb 9, 2012 1:36:24 AM (12 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r107196 r107197 1 2012-02-09 Roland Steiner <rolandsteiner@chromium.org> 2 3 SelectorChecker::checkSelector: move parameters into a struct 4 https://bugs.webkit.org/show_bug.cgi?id=77525 5 6 Added 'SelectorCheckingContext' struct to hold parameters for the function. 7 Adapted calling sites. 8 9 Reviewed by Antti Koivisto. 10 11 No new tests. (refactoring) 12 13 * css/CSSStyleSelector.cpp: 14 (WebCore::CSSStyleSelector::checkSelector): 15 * css/SelectorChecker.cpp: 16 (WebCore::SelectorChecker::checkSelector): 17 (WebCore): 18 (WebCore::SelectorChecker::checkOneSelector): 19 * css/SelectorChecker.h: 20 (SelectorCheckingContext): 21 (WebCore::SelectorChecker::SelectorCheckingContext::SelectorCheckingContext): 22 (SelectorChecker): 23 1 24 2012-02-09 Kent Tamura <tkent@chromium.org> 2 25 -
trunk/Source/WebCore/css/CSSStyleSelector.cpp
r107193 r107197 2093 2093 2094 2094 // Slow path. 2095 SelectorChecker::SelectorMatch match = m_checker.checkSelector(ruleData.selector(), m_element, m_dynamicPseudo, false, SelectorChecker::VisitedMatchEnabled, style(), m_parentNode ? m_parentNode->renderStyle() : 0); 2095 SelectorChecker::SelectorCheckingContext context(ruleData.selector(), m_element, SelectorChecker::VisitedMatchEnabled, style(), m_parentNode ? m_parentNode->renderStyle() : 0); 2096 SelectorChecker::SelectorMatch match = m_checker.checkSelector(context, m_dynamicPseudo); 2096 2097 if (match != SelectorChecker::SelectorMatches) 2097 2098 return false; -
trunk/Source/WebCore/css/SelectorChecker.cpp
r106833 r107197 269 269 bool SelectorChecker::checkSelector(CSSSelector* sel, Element* element, bool isFastCheckableSelector) const 270 270 { 271 PseudoId dynamicPseudo = NOPSEUDO;272 271 if (isFastCheckableSelector && !element->isSVGElement()) { 273 272 if (!fastCheckRightmostSelector(sel, element, VisitedMatchDisabled)) … … 275 274 return fastCheckSelector(sel, element); 276 275 } 277 return checkSelector(sel, element, dynamicPseudo, false, VisitedMatchDisabled) == SelectorMatches; 276 277 PseudoId dynamicPseudo = NOPSEUDO; 278 return checkSelector(SelectorCheckingContext(sel, element, SelectorChecker::VisitedMatchDisabled), dynamicPseudo) == SelectorMatches; 278 279 } 279 280 … … 443 444 // * SelectorFailsAllSiblings - the selector fails for e and any sibling of e 444 445 // * SelectorFailsCompletely - the selector fails for e and any sibling or ancestor of e 445 SelectorChecker::SelectorMatch SelectorChecker::checkSelector( CSSSelector* sel, Element* e, PseudoId& dynamicPseudo, bool isSubSelector, VisitedMatchType visitedMatchType, RenderStyle* elementStyle, RenderStyle* elementParentStyle) const446 SelectorChecker::SelectorMatch SelectorChecker::checkSelector(const SelectorCheckingContext& context, PseudoId& dynamicPseudo) const 446 447 { 447 448 #if ENABLE(SVG) 448 449 // Spec: CSS2 selectors cannot be applied to the (conceptually) cloned DOM tree 449 450 // because its contents are not part of the formal document structure. 450 if ( e->isSVGShadowRoot())451 if (context.element->isSVGShadowRoot()) 451 452 return SelectorFailsCompletely; 452 453 #endif 453 454 454 455 // first selector has to match 455 if (!checkOneSelector( sel, e, dynamicPseudo, isSubSelector, visitedMatchType, elementStyle, elementParentStyle))456 if (!checkOneSelector(context, dynamicPseudo)) 456 457 return SelectorFailsLocally; 457 458 458 459 // The rest of the selectors has to match 459 CSSSelector::Relation relation = sel->relation();460 461 // Prepare next sel 462 sel = sel->tagHistory();463 if (! sel)460 CSSSelector::Relation relation = context.selector->relation(); 461 462 // Prepare next selector 463 CSSSelector* historySelector = context.selector->tagHistory(); 464 if (!historySelector) 464 465 return SelectorMatches; 466 467 SelectorCheckingContext nextContext(context); 468 nextContext.selector = historySelector; 465 469 466 470 if (relation != CSSSelector::SubSelector) { … … 470 474 471 475 // Disable :visited matching when we see the first link or try to match anything else than an ancestors. 472 if (! isSubSelector && (e->isLink() || (relation != CSSSelector::Descendant && relation != CSSSelector::Child)))473 visitedMatchType = VisitedMatchDisabled;476 if (!context.isSubSelector && (context.element->isLink() || (relation != CSSSelector::Descendant && relation != CSSSelector::Child))) 477 nextContext.visitedMatchType = VisitedMatchDisabled; 474 478 } 475 479 476 480 switch (relation) { 477 481 case CSSSelector::Descendant: 478 while (true) {479 ContainerNode* n = e->parentNode();480 if (!n || !n->isElementNode())481 return SelectorFailsCompletely;482 e = static_cast<Element*>(n);483 SelectorMatch match = checkSelector( sel, e, dynamicPseudo, false, visitedMatchType);482 nextContext.element = context.element->parentElement(); 483 nextContext.isSubSelector = false; 484 nextContext.elementStyle = 0; 485 nextContext.elementParentStyle = 0; 486 for (; nextContext.element; nextContext.element = nextContext.element->parentElement()) { 487 SelectorMatch match = checkSelector(nextContext, dynamicPseudo); 484 488 if (match == SelectorMatches || match == SelectorFailsCompletely) 485 489 return match; 486 490 } 487 break; 491 return SelectorFailsCompletely; 492 488 493 case CSSSelector::Child: 489 { 490 ContainerNode* n = e->parentNode(); 491 if (!n || !n->isElementNode()) 492 return SelectorFailsCompletely; 493 e = static_cast<Element*>(n); 494 return checkSelector(sel, e, dynamicPseudo, false, visitedMatchType); 495 } 494 nextContext.element = context.element->parentElement(); 495 if (!nextContext.element) 496 return SelectorFailsCompletely; 497 nextContext.isSubSelector = false; 498 nextContext.elementStyle = 0; 499 nextContext.elementParentStyle = 0; 500 return checkSelector(nextContext, dynamicPseudo); 501 496 502 case CSSSelector::DirectAdjacent: 497 { 498 if (!m_isCollectingRulesOnly && e->parentNode() && e->parentNode()->isElementNode()) { 499 RenderStyle* parentStyle = elementStyle ? elementParentStyle : e->parentNode()->renderStyle(); 500 if (parentStyle) 501 parentStyle->setChildrenAffectedByDirectAdjacentRules(); 502 } 503 e = e->previousElementSibling(); 504 if (!e) 505 return SelectorFailsAllSiblings; 506 return checkSelector(sel, e, dynamicPseudo, false, visitedMatchType); 507 } 503 if (!m_isCollectingRulesOnly && context.element->parentElement()) { 504 RenderStyle* parentStyle = context.elementStyle ? context.elementParentStyle : context.element->parentNode()->renderStyle(); 505 if (parentStyle) 506 parentStyle->setChildrenAffectedByDirectAdjacentRules(); 507 } 508 nextContext.element = context.element->previousElementSibling(); 509 if (!nextContext.element) 510 return SelectorFailsAllSiblings; 511 nextContext.isSubSelector = false; 512 nextContext.elementStyle = 0; 513 nextContext.elementParentStyle = 0; 514 return checkSelector(nextContext, dynamicPseudo); 515 508 516 case CSSSelector::IndirectAdjacent: 509 if (!m_isCollectingRulesOnly && e->parentNode() && e->parentNode()->isElementNode()) {510 RenderStyle* parentStyle = elementStyle ? elementParentStyle : e->parentNode()->renderStyle();517 if (!m_isCollectingRulesOnly && context.element->parentElement()) { 518 RenderStyle* parentStyle = context.elementStyle ? context.elementParentStyle : context.element->parentNode()->renderStyle(); 511 519 if (parentStyle) 512 520 parentStyle->setChildrenAffectedByForwardPositionalRules(); 513 521 } 514 while (true) { 515 e = e->previousElementSibling(); 516 if (!e) 517 return SelectorFailsAllSiblings; 518 SelectorMatch match = checkSelector(sel, e, dynamicPseudo, false, visitedMatchType); 522 nextContext.element = context.element->previousElementSibling(); 523 nextContext.isSubSelector = false; 524 nextContext.elementStyle = 0; 525 nextContext.elementParentStyle = 0; 526 for (; nextContext.element; nextContext.element = nextContext.element->previousElementSibling()) { 527 SelectorMatch match = checkSelector(nextContext, dynamicPseudo); 519 528 if (match == SelectorMatches || match == SelectorFailsAllSiblings || match == SelectorFailsCompletely) 520 529 return match; 521 530 }; 522 break; 531 return SelectorFailsAllSiblings; 532 523 533 case CSSSelector::SubSelector: 524 534 // a selector is invalid if something follows a pseudo-element 525 535 // We make an exception for scrollbar pseudo elements and allow a set of pseudo classes (but nothing else) 526 536 // to follow the pseudo elements. 527 if (( elementStyle || m_isCollectingRulesOnly) && dynamicPseudo != NOPSEUDO && dynamicPseudo != SELECTION528 && !((RenderScrollbar::scrollbarForStyleResolve() || dynamicPseudo == SCROLLBAR_CORNER || dynamicPseudo == RESIZER) && sel->m_match == CSSSelector::PseudoClass))537 if ((context.elementStyle || m_isCollectingRulesOnly) && dynamicPseudo != NOPSEUDO && dynamicPseudo != SELECTION 538 && !((RenderScrollbar::scrollbarForStyleResolve() || dynamicPseudo == SCROLLBAR_CORNER || dynamicPseudo == RESIZER) && context.selector->m_match == CSSSelector::PseudoClass)) 529 539 return SelectorFailsCompletely; 530 return checkSelector(sel, e, dynamicPseudo, true, visitedMatchType, elementStyle, elementParentStyle); 540 nextContext.isSubSelector = true; 541 return checkSelector(nextContext, dynamicPseudo); 542 531 543 case CSSSelector::ShadowDescendant: 532 544 { 533 Node* shadowHostNode = e->shadowAncestorNode();534 if (shadowHostNode == e|| !shadowHostNode->isElementNode())545 Node* shadowHostNode = context.element->shadowAncestorNode(); 546 if (shadowHostNode == context.element || !shadowHostNode->isElementNode()) 535 547 return SelectorFailsCompletely; 536 e = static_cast<Element*>(shadowHostNode); 537 return checkSelector(sel, e, dynamicPseudo, false, visitedMatchType); 538 } 539 } 540 548 nextContext.element = toElement(shadowHostNode); 549 nextContext.isSubSelector = false; 550 nextContext.elementStyle = 0; 551 nextContext.elementParentStyle = 0; 552 return checkSelector(nextContext, dynamicPseudo); 553 } 554 } 555 556 ASSERT_NOT_REACHED(); 541 557 return SelectorFailsCompletely; 542 558 } … … 688 704 } 689 705 690 bool SelectorChecker::checkOneSelector(CSSSelector* sel, Element* e, PseudoId& dynamicPseudo, bool isSubSelector, VisitedMatchType visitedMatchType, RenderStyle* elementStyle, RenderStyle* elementParentStyle) const 691 { 692 ASSERT(e); 693 if (!SelectorChecker::tagMatches(e, sel)) 706 bool SelectorChecker::checkOneSelector(const SelectorCheckingContext& context, PseudoId& dynamicPseudo) const 707 { 708 Element* const & element = context.element; 709 CSSSelector* const & selector = context.selector; 710 ASSERT(element); 711 ASSERT(selector); 712 713 if (!SelectorChecker::tagMatches(element, selector)) 694 714 return false; 695 715 696 if (sel ->m_match == CSSSelector::Class)697 return e ->hasClass() && static_cast<StyledElement*>(e)->classNames().contains(sel->value());698 699 if (sel ->m_match == CSSSelector::Id)700 return e ->hasID() && e->idForStyleResolution() == sel->value();701 702 if (sel ->isAttributeSelector()) {703 const QualifiedName& attr = sel ->attribute();704 705 if (!e ->hasAttributes())716 if (selector->m_match == CSSSelector::Class) 717 return element->hasClass() && static_cast<StyledElement*>(element)->classNames().contains(selector->value()); 718 719 if (selector->m_match == CSSSelector::Id) 720 return element->hasID() && element->idForStyleResolution() == selector->value(); 721 722 if (selector->isAttributeSelector()) { 723 const QualifiedName& attr = selector->attribute(); 724 725 if (!element->hasAttributes()) 706 726 return false; 707 727 708 728 bool caseSensitive = !m_documentIsHTML || !htmlAttributeHasCaseInsensitiveValue(attr); 709 729 710 if (!anyAttributeMatches(e , static_cast<CSSSelector::Match>(sel->m_match), attr, sel->value(), caseSensitive))711 return false; 712 } 713 714 if (sel ->m_match == CSSSelector::PseudoClass) {730 if (!anyAttributeMatches(element, static_cast<CSSSelector::Match>(selector->m_match), attr, selector->value(), caseSensitive)) 731 return false; 732 } 733 734 if (selector->m_match == CSSSelector::PseudoClass) { 715 735 // Handle :not up front. 716 if (sel->pseudoType() == CSSSelector::PseudoNot) { 717 ASSERT(sel->selectorList()); 718 for (CSSSelector* subSel = sel->selectorList()->first(); subSel; subSel = subSel->tagHistory()) { 736 if (selector->pseudoType() == CSSSelector::PseudoNot) { 737 ASSERT(selector->selectorList()); 738 SelectorCheckingContext subContext(context); 739 subContext.isSubSelector = true; 740 for (subContext.selector = selector->selectorList()->first(); subContext.selector; subContext.selector = subContext.selector->tagHistory()) { 719 741 // :not cannot nest. I don't really know why this is a 720 742 // restriction in CSS3, but it is, so let's honor it. 721 743 // the parser enforces that this never occurs 722 ASSERT(sub Sel->pseudoType() != CSSSelector::PseudoNot);744 ASSERT(subContext.selector->pseudoType() != CSSSelector::PseudoNot); 723 745 // We select between :visited and :link when applying. We don't know which one applied (or not) yet. 724 if (sub Sel->pseudoType() == CSSSelector::PseudoVisited || (subSel->pseudoType() == CSSSelector::PseudoLink &&visitedMatchType == VisitedMatchEnabled))746 if (subContext.selector->pseudoType() == CSSSelector::PseudoVisited || (subContext.selector->pseudoType() == CSSSelector::PseudoLink && subContext.visitedMatchType == VisitedMatchEnabled)) 725 747 return true; 726 if (!checkOneSelector(sub Sel, e, dynamicPseudo, true, visitedMatchType, elementStyle, elementParentStyle))748 if (!checkOneSelector(subContext, dynamicPseudo)) 727 749 return true; 728 750 } … … 730 752 // CSS scrollbars match a specific subset of pseudo classes, and they have specialized rules for each 731 753 // (since there are no elements involved). 732 return checkScrollbarPseudoClass(sel , dynamicPseudo);754 return checkScrollbarPseudoClass(selector, dynamicPseudo); 733 755 } else if (dynamicPseudo == SELECTION) { 734 if (sel ->pseudoType() == CSSSelector::PseudoWindowInactive)756 if (selector->pseudoType() == CSSSelector::PseudoWindowInactive) 735 757 return !m_document->page()->focusController()->isActive(); 736 758 } 737 759 738 760 // Normal element pseudo class checking. 739 switch (sel ->pseudoType()) {761 switch (selector->pseudoType()) { 740 762 // Pseudo classes: 741 763 case CSSSelector::PseudoNot: … … 744 766 { 745 767 bool result = true; 746 for (Node* n = e ->firstChild(); n; n = n->nextSibling()) {768 for (Node* n = element->firstChild(); n; n = n->nextSibling()) { 747 769 if (n->isElementNode()) { 748 770 result = false; … … 758 780 } 759 781 if (!m_isCollectingRulesOnly) { 760 if ( elementStyle)761 elementStyle->setEmptyState(result);762 else if (e ->renderStyle() && (e->document()->usesSiblingRules() || e->renderStyle()->unique()))763 e ->renderStyle()->setEmptyState(result);782 if (context.elementStyle) 783 context.elementStyle->setEmptyState(result); 784 else if (element->renderStyle() && (element->document()->usesSiblingRules() || element->renderStyle()->unique())) 785 element->renderStyle()->setEmptyState(result); 764 786 } 765 787 return result; … … 767 789 case CSSSelector::PseudoFirstChild: 768 790 // first-child matches the first child that is an element 769 if (e ->parentElement()) {791 if (element->parentElement()) { 770 792 bool result = false; 771 if (!e ->previousElementSibling())793 if (!element->previousElementSibling()) 772 794 result = true; 773 795 if (!m_isCollectingRulesOnly) { 774 RenderStyle* childStyle = elementStyle ? elementStyle : e->renderStyle();775 RenderStyle* parentStyle = elementStyle ? elementParentStyle : e->parentNode()->renderStyle();796 RenderStyle* childStyle = context.elementStyle ? context.elementStyle : element->renderStyle(); 797 RenderStyle* parentStyle = context.elementStyle ? context.elementParentStyle : element->parentNode()->renderStyle(); 776 798 if (parentStyle) 777 799 parentStyle->setChildrenAffectedByFirstChildRules(); … … 784 806 case CSSSelector::PseudoFirstOfType: 785 807 // first-of-type matches the first element of its type 786 if (e ->parentElement()) {808 if (element->parentElement()) { 787 809 bool result = true; 788 const QualifiedName& type = e ->tagQName();789 for (const Element* sibling = e ->previousElementSibling(); sibling; sibling = sibling->previousElementSibling()) {810 const QualifiedName& type = element->tagQName(); 811 for (const Element* sibling = element->previousElementSibling(); sibling; sibling = sibling->previousElementSibling()) { 790 812 if (sibling->hasTagName(type)) { 791 813 result = false; … … 794 816 } 795 817 if (!m_isCollectingRulesOnly) { 796 RenderStyle* parentStyle = elementStyle ? elementParentStyle : e->parentNode()->renderStyle();818 RenderStyle* parentStyle = context.elementStyle ? context.elementParentStyle : element->parentNode()->renderStyle(); 797 819 if (parentStyle) 798 820 parentStyle->setChildrenAffectedByForwardPositionalRules(); … … 803 825 case CSSSelector::PseudoLastChild: 804 826 // last-child matches the last child that is an element 805 if (Element* parentElement = e ->parentElement()) {806 bool result = parentElement->isFinishedParsingChildren() && !e ->nextElementSibling();827 if (Element* parentElement = element->parentElement()) { 828 bool result = parentElement->isFinishedParsingChildren() && !element->nextElementSibling(); 807 829 if (!m_isCollectingRulesOnly) { 808 RenderStyle* childStyle = elementStyle ? elementStyle : e->renderStyle();809 RenderStyle* parentStyle = elementStyle ?elementParentStyle : parentElement->renderStyle();830 RenderStyle* childStyle = context.elementStyle ? context.elementStyle : element->renderStyle(); 831 RenderStyle* parentStyle = context.elementStyle ? context.elementParentStyle : parentElement->renderStyle(); 810 832 if (parentStyle) 811 833 parentStyle->setChildrenAffectedByLastChildRules(); … … 818 840 case CSSSelector::PseudoLastOfType: 819 841 // last-of-type matches the last element of its type 820 if (Element* parentElement = e ->parentElement()) {842 if (Element* parentElement = element->parentElement()) { 821 843 if (!m_isCollectingRulesOnly) { 822 RenderStyle* parentStyle = elementStyle ?elementParentStyle : parentElement->renderStyle();844 RenderStyle* parentStyle = context.elementStyle ? context.elementParentStyle : parentElement->renderStyle(); 823 845 if (parentStyle) 824 846 parentStyle->setChildrenAffectedByBackwardPositionalRules(); … … 826 848 if (!parentElement->isFinishedParsingChildren()) 827 849 return false; 828 const QualifiedName& type = e ->tagQName();829 for (const Element* sibling = e ->nextElementSibling(); sibling; sibling = sibling->nextElementSibling()) {850 const QualifiedName& type = element->tagQName(); 851 for (const Element* sibling = element->nextElementSibling(); sibling; sibling = sibling->nextElementSibling()) { 830 852 if (sibling->hasTagName(type)) 831 853 return false; … … 835 857 break; 836 858 case CSSSelector::PseudoOnlyChild: 837 if (Element* parentElement = e ->parentElement()) {838 bool firstChild = !e ->previousElementSibling();839 bool onlyChild = firstChild && parentElement->isFinishedParsingChildren() && !e ->nextElementSibling();859 if (Element* parentElement = element->parentElement()) { 860 bool firstChild = !element->previousElementSibling(); 861 bool onlyChild = firstChild && parentElement->isFinishedParsingChildren() && !element->nextElementSibling(); 840 862 841 863 if (!m_isCollectingRulesOnly) { 842 RenderStyle* childStyle = elementStyle ? elementStyle : e->renderStyle();843 RenderStyle* parentStyle = elementStyle ?elementParentStyle : parentElement->renderStyle();864 RenderStyle* childStyle = context.elementStyle ? context.elementStyle : element->renderStyle(); 865 RenderStyle* parentStyle = context.elementStyle ? context.elementParentStyle : parentElement->renderStyle(); 844 866 if (parentStyle) { 845 867 parentStyle->setChildrenAffectedByFirstChildRules(); … … 856 878 case CSSSelector::PseudoOnlyOfType: 857 879 // FIXME: This selector is very slow. 858 if (Element* parentElement = e ->parentElement()) {880 if (Element* parentElement = element->parentElement()) { 859 881 if (!m_isCollectingRulesOnly) { 860 RenderStyle* parentStyle = elementStyle ?elementParentStyle : parentElement->renderStyle();882 RenderStyle* parentStyle = context.elementStyle ? context.elementParentStyle : parentElement->renderStyle(); 861 883 if (parentStyle) { 862 884 parentStyle->setChildrenAffectedByForwardPositionalRules(); … … 866 888 if (!parentElement->isFinishedParsingChildren()) 867 889 return false; 868 const QualifiedName& type = e ->tagQName();869 for (const Element* sibling = e ->previousElementSibling(); sibling; sibling = sibling->previousElementSibling()) {890 const QualifiedName& type = element->tagQName(); 891 for (const Element* sibling = element->previousElementSibling(); sibling; sibling = sibling->previousElementSibling()) { 870 892 if (sibling->hasTagName(type)) 871 893 return false; 872 894 } 873 for (const Element* sibling = e ->nextElementSibling(); sibling; sibling = sibling->nextElementSibling()) {895 for (const Element* sibling = element->nextElementSibling(); sibling; sibling = sibling->nextElementSibling()) { 874 896 if (sibling->hasTagName(type)) 875 897 return false; … … 879 901 break; 880 902 case CSSSelector::PseudoNthChild: 881 if (!sel ->parseNth())903 if (!selector->parseNth()) 882 904 break; 883 if (Element* parentElement = e ->parentElement()) {905 if (Element* parentElement = element->parentElement()) { 884 906 int count = 1; 885 for (const Element* sibling = e ->previousElementSibling(); sibling; sibling = sibling->previousElementSibling()) {907 for (const Element* sibling = element->previousElementSibling(); sibling; sibling = sibling->previousElementSibling()) { 886 908 RenderStyle* s = sibling->renderStyle(); 887 909 unsigned index = s ? s->childIndex() : 0; … … 894 916 895 917 if (!m_isCollectingRulesOnly) { 896 RenderStyle* childStyle = elementStyle ? elementStyle : e->renderStyle();897 RenderStyle* parentStyle = elementStyle ?elementParentStyle : parentElement->renderStyle();918 RenderStyle* childStyle = context.elementStyle ? context.elementStyle : element->renderStyle(); 919 RenderStyle* parentStyle = context.elementStyle ? context.elementParentStyle : parentElement->renderStyle(); 898 920 if (childStyle) 899 921 childStyle->setChildIndex(count); … … 902 924 } 903 925 904 if (sel ->matchNth(count))926 if (selector->matchNth(count)) 905 927 return true; 906 928 } 907 929 break; 908 930 case CSSSelector::PseudoNthOfType: 909 if (!sel ->parseNth())931 if (!selector->parseNth()) 910 932 break; 911 if (Element* parentElement = e ->parentElement()) {933 if (Element* parentElement = element->parentElement()) { 912 934 int count = 1; 913 const QualifiedName& type = e ->tagQName();914 for (const Element* sibling = e ->previousElementSibling(); sibling; sibling = sibling->previousElementSibling()) {935 const QualifiedName& type = element->tagQName(); 936 for (const Element* sibling = element->previousElementSibling(); sibling; sibling = sibling->previousElementSibling()) { 915 937 if (sibling->hasTagName(type)) 916 938 ++count; 917 939 } 918 940 if (!m_isCollectingRulesOnly) { 919 RenderStyle* parentStyle = elementStyle ?elementParentStyle : parentElement->renderStyle();941 RenderStyle* parentStyle = context.elementStyle ? context.elementParentStyle : parentElement->renderStyle(); 920 942 if (parentStyle) 921 943 parentStyle->setChildrenAffectedByForwardPositionalRules(); 922 944 } 923 945 924 if (sel ->matchNth(count))946 if (selector->matchNth(count)) 925 947 return true; 926 948 } 927 949 break; 928 950 case CSSSelector::PseudoNthLastChild: 929 if (!sel ->parseNth())951 if (!selector->parseNth()) 930 952 break; 931 if (Element* parentElement = e ->parentElement()) {953 if (Element* parentElement = element->parentElement()) { 932 954 if (!m_isCollectingRulesOnly) { 933 RenderStyle* parentStyle = elementStyle ?elementParentStyle : parentElement->renderStyle();955 RenderStyle* parentStyle = context.elementStyle ? context.elementParentStyle : parentElement->renderStyle(); 934 956 if (parentStyle) 935 957 parentStyle->setChildrenAffectedByBackwardPositionalRules(); … … 938 960 return false; 939 961 int count = 1; 940 for (const Element* sibling = e ->nextElementSibling(); sibling; sibling = sibling->nextElementSibling())962 for (const Element* sibling = element->nextElementSibling(); sibling; sibling = sibling->nextElementSibling()) 941 963 ++count; 942 if (sel ->matchNth(count))964 if (selector->matchNth(count)) 943 965 return true; 944 966 } 945 967 break; 946 968 case CSSSelector::PseudoNthLastOfType: 947 if (!sel ->parseNth())969 if (!selector->parseNth()) 948 970 break; 949 if (Element* parentElement = e ->parentElement()) {971 if (Element* parentElement = element->parentElement()) { 950 972 if (!m_isCollectingRulesOnly) { 951 RenderStyle* parentStyle = elementStyle ?elementParentStyle : parentElement->renderStyle();973 RenderStyle* parentStyle = context.elementStyle ? context.elementParentStyle : parentElement->renderStyle(); 952 974 if (parentStyle) 953 975 parentStyle->setChildrenAffectedByBackwardPositionalRules(); … … 956 978 return false; 957 979 int count = 1; 958 const QualifiedName& type = e ->tagQName();959 for (const Element* sibling = e ->nextElementSibling(); sibling; sibling = sibling->nextElementSibling()) {980 const QualifiedName& type = element->tagQName(); 981 for (const Element* sibling = element->nextElementSibling(); sibling; sibling = sibling->nextElementSibling()) { 960 982 if (sibling->hasTagName(type)) 961 983 ++count; 962 984 } 963 if (sel ->matchNth(count))985 if (selector->matchNth(count)) 964 986 return true; 965 987 } 966 988 break; 967 989 case CSSSelector::PseudoTarget: 968 if (e == e->document()->cssTarget())990 if (element == element->document()->cssTarget()) 969 991 return true; 970 992 break; 971 993 case CSSSelector::PseudoAny: 972 for (CSSSelector* selector = sel->selectorList()->first(); selector; selector = CSSSelectorList::next(selector)) { 973 if (checkSelector(selector, e, dynamicPseudo, true, visitedMatchType, elementStyle, elementParentStyle) == SelectorMatches) 974 return true; 994 { 995 SelectorCheckingContext subContext(context); 996 subContext.isSubSelector = true; 997 for (subContext.selector = selector->selectorList()->first(); subContext.selector; subContext.selector = CSSSelectorList::next(subContext.selector)) { 998 if (checkSelector(subContext, dynamicPseudo) == SelectorMatches) 999 return true; 1000 } 975 1001 } 976 1002 break; 977 1003 case CSSSelector::PseudoAutofill: 978 if (!e || !e->isFormControlElement())1004 if (!element || !element->isFormControlElement()) 979 1005 break; 980 if (HTMLInputElement* inputElement = e ->toInputElement())1006 if (HTMLInputElement* inputElement = element->toInputElement()) 981 1007 return inputElement->isAutofilled(); 982 1008 break; … … 984 1010 case CSSSelector::PseudoLink: 985 1011 // :visited and :link matches are separated later when applying the style. Here both classes match all links... 986 return e ->isLink();1012 return element->isLink(); 987 1013 case CSSSelector::PseudoVisited: 988 1014 // ...except if :visited matching is disabled for ancestor/sibling matching. 989 return e ->isLink() &&visitedMatchType == VisitedMatchEnabled;1015 return element->isLink() && context.visitedMatchType == VisitedMatchEnabled; 990 1016 case CSSSelector::PseudoDrag: 991 if ( elementStyle)992 elementStyle->setAffectedByDragRules(true);993 else if (e ->renderStyle())994 e ->renderStyle()->setAffectedByDragRules(true);995 if (e ->renderer() && e->renderer()->isDragging())1017 if (context.elementStyle) 1018 context.elementStyle->setAffectedByDragRules(true); 1019 else if (element->renderStyle()) 1020 element->renderStyle()->setAffectedByDragRules(true); 1021 if (element->renderer() && element->renderer()->isDragging()) 996 1022 return true; 997 1023 break; 998 1024 case CSSSelector::PseudoFocus: 999 return matchesFocusPseudoClass(e );1025 return matchesFocusPseudoClass(element); 1000 1026 case CSSSelector::PseudoHover: 1001 1027 // If we're in quirks mode, then hover should never match anchors with no 1002 1028 // href and *:hover should not match anything. This is important for sites like wsj.com. 1003 if (m_strictParsing || isSubSelector || (sel->hasTag() && !e->hasTagName(aTag)) || e->isLink()) {1004 if ( elementStyle)1005 elementStyle->setAffectedByHoverRules(true);1006 else if (e ->renderStyle())1007 e ->renderStyle()->setAffectedByHoverRules(true);1008 if (e ->hovered() || InspectorInstrumentation::forcePseudoState(e, CSSSelector::PseudoHover))1029 if (m_strictParsing || context.isSubSelector || (selector->hasTag() && !element->hasTagName(aTag)) || element->isLink()) { 1030 if (context.elementStyle) 1031 context.elementStyle->setAffectedByHoverRules(true); 1032 else if (element->renderStyle()) 1033 element->renderStyle()->setAffectedByHoverRules(true); 1034 if (element->hovered() || InspectorInstrumentation::forcePseudoState(element, CSSSelector::PseudoHover)) 1009 1035 return true; 1010 1036 } … … 1013 1039 // If we're in quirks mode, then :active should never match anchors with no 1014 1040 // href and *:active should not match anything. 1015 if (m_strictParsing || isSubSelector || (sel->hasTag() && !e->hasTagName(aTag)) || e->isLink()) {1016 if ( elementStyle)1017 elementStyle->setAffectedByActiveRules(true);1018 else if (e ->renderStyle())1019 e ->renderStyle()->setAffectedByActiveRules(true);1020 if (e ->active() || InspectorInstrumentation::forcePseudoState(e, CSSSelector::PseudoActive))1041 if (m_strictParsing || context.isSubSelector || (selector->hasTag() && !element->hasTagName(aTag)) || element->isLink()) { 1042 if (context.elementStyle) 1043 context.elementStyle->setAffectedByActiveRules(true); 1044 else if (element->renderStyle()) 1045 element->renderStyle()->setAffectedByActiveRules(true); 1046 if (element->active() || InspectorInstrumentation::forcePseudoState(element, CSSSelector::PseudoActive)) 1021 1047 return true; 1022 1048 } 1023 1049 break; 1024 1050 case CSSSelector::PseudoEnabled: 1025 if (e && e->isFormControlElement())1026 return e ->isEnabledFormControl();1051 if (element && element->isFormControlElement()) 1052 return element->isEnabledFormControl(); 1027 1053 break; 1028 1054 case CSSSelector::PseudoFullPageMedia: 1029 return e && e->document() && e->document()->isMediaDocument();1055 return element && element->document() && element->document()->isMediaDocument(); 1030 1056 break; 1031 1057 case CSSSelector::PseudoDefault: 1032 return e && e->isDefaultButtonForForm();1058 return element && element->isDefaultButtonForForm(); 1033 1059 case CSSSelector::PseudoDisabled: 1034 if (e && e->isFormControlElement())1035 return !e ->isEnabledFormControl();1060 if (element && element->isFormControlElement()) 1061 return !element->isEnabledFormControl(); 1036 1062 break; 1037 1063 case CSSSelector::PseudoReadOnly: 1038 if (!e || !e->isFormControlElement())1039 return false; 1040 return e ->isTextFormControl() && e->isReadOnlyFormControl();1064 if (!element || !element->isFormControlElement()) 1065 return false; 1066 return element->isTextFormControl() && element->isReadOnlyFormControl(); 1041 1067 case CSSSelector::PseudoReadWrite: 1042 if (!e || !e->isFormControlElement())1043 return false; 1044 return e ->isTextFormControl() && !e->isReadOnlyFormControl();1068 if (!element || !element->isFormControlElement()) 1069 return false; 1070 return element->isTextFormControl() && !element->isReadOnlyFormControl(); 1045 1071 case CSSSelector::PseudoOptional: 1046 return e && e->isOptionalFormControl();1072 return element && element->isOptionalFormControl(); 1047 1073 case CSSSelector::PseudoRequired: 1048 return e && e->isRequiredFormControl();1074 return element && element->isRequiredFormControl(); 1049 1075 case CSSSelector::PseudoValid: 1050 if (!e )1051 return false; 1052 e ->document()->setContainsValidityStyleRules();1053 return e ->willValidate() && e->isValidFormControlElement();1076 if (!element) 1077 return false; 1078 element->document()->setContainsValidityStyleRules(); 1079 return element->willValidate() && element->isValidFormControlElement(); 1054 1080 case CSSSelector::PseudoInvalid: 1055 if (!e )1056 return false; 1057 e ->document()->setContainsValidityStyleRules();1058 return (e ->willValidate() && !e->isValidFormControlElement()) || e->hasUnacceptableValue();1081 if (!element) 1082 return false; 1083 element->document()->setContainsValidityStyleRules(); 1084 return (element->willValidate() && !element->isValidFormControlElement()) || element->hasUnacceptableValue(); 1059 1085 case CSSSelector::PseudoChecked: 1060 1086 { 1061 if (!e || !e->isFormControlElement())1087 if (!element || !element->isFormControlElement()) 1062 1088 break; 1063 1089 // Even though WinIE allows checked and indeterminate to co-exist, the CSS selector spec says that 1064 1090 // you can't be both checked and indeterminate. We will behave like WinIE behind the scenes and just 1065 1091 // obey the CSS spec here in the test for matching the pseudo. 1066 HTMLInputElement* inputElement = e ->toInputElement();1092 HTMLInputElement* inputElement = element->toInputElement(); 1067 1093 if (inputElement && inputElement->shouldAppearChecked() && !inputElement->isIndeterminate()) 1068 1094 return true; 1069 if (e ->hasTagName(optionTag) && toHTMLOptionElement(e)->selected())1095 if (element->hasTagName(optionTag) && toHTMLOptionElement(element)->selected()) 1070 1096 return true; 1071 1097 break; … … 1073 1099 case CSSSelector::PseudoIndeterminate: 1074 1100 { 1075 if (!e || !e->isFormControlElement())1101 if (!element || !element->isFormControlElement()) 1076 1102 break; 1077 1103 #if ENABLE(PROGRESS_TAG) 1078 if (e ->hasTagName(progressTag)) {1079 HTMLProgressElement* progress = static_cast<HTMLProgressElement*>(e );1104 if (element->hasTagName(progressTag)) { 1105 HTMLProgressElement* progress = static_cast<HTMLProgressElement*>(element); 1080 1106 if (progress && !progress->isDeterminate()) 1081 1107 return true; … … 1083 1109 } 1084 1110 #endif 1085 HTMLInputElement* inputElement = e ->toInputElement();1111 HTMLInputElement* inputElement = element->toInputElement(); 1086 1112 if (inputElement && inputElement->isIndeterminate()) 1087 1113 return true; … … 1089 1115 } 1090 1116 case CSSSelector::PseudoRoot: 1091 if (e == e->document()->documentElement())1117 if (element == element->document()->documentElement()) 1092 1118 return true; 1093 1119 break; 1094 1120 case CSSSelector::PseudoLang: 1095 1121 { 1096 AtomicString value = e ->computeInheritedLanguage();1097 const AtomicString& argument = sel ->argument();1122 AtomicString value = element->computeInheritedLanguage(); 1123 const AtomicString& argument = selector->argument(); 1098 1124 if (value.isEmpty() || !value.startsWith(argument, false)) 1099 1125 break; … … 1108 1134 // that element. Also, an <iframe>, <object> or <embed> element whose child browsing 1109 1135 // context's Document is in the fullscreen state has the 'full-screen' pseudoclass applied. 1110 if (e ->isFrameElementBase() && static_cast<HTMLFrameElementBase*>(e)->containsFullScreenElement())1136 if (element->isFrameElementBase() && static_cast<HTMLFrameElementBase*>(element)->containsFullScreenElement()) 1111 1137 return true; 1112 if (!e ->document()->webkitIsFullScreen())1113 return false; 1114 return e == e->document()->webkitCurrentFullScreenElement();1138 if (!element->document()->webkitIsFullScreen()) 1139 return false; 1140 return element == element->document()->webkitCurrentFullScreenElement(); 1115 1141 case CSSSelector::PseudoAnimatingFullScreenTransition: 1116 if (e != e->document()->webkitCurrentFullScreenElement())1117 return false; 1118 return e ->document()->isAnimatingFullScreen();1142 if (element != element->document()->webkitCurrentFullScreenElement()) 1143 return false; 1144 return element->document()->isAnimatingFullScreen(); 1119 1145 case CSSSelector::PseudoFullScreenAncestor: 1120 return e ->containsFullScreenElement();1146 return element->containsFullScreenElement(); 1121 1147 case CSSSelector::PseudoFullScreenDocument: 1122 1148 // While a Document is in the fullscreen state, the 'full-screen-document' pseudoclass applies 1123 1149 // to all elements of that Document. 1124 if (!e ->document()->webkitIsFullScreen())1150 if (!element->document()->webkitIsFullScreen()) 1125 1151 return false; 1126 1152 return true; 1127 1153 #endif 1128 1154 case CSSSelector::PseudoInRange: 1129 if (!e )1130 return false; 1131 e ->document()->setContainsValidityStyleRules();1132 return e ->isInRange();1155 if (!element) 1156 return false; 1157 element->document()->setContainsValidityStyleRules(); 1158 return element->isInRange(); 1133 1159 case CSSSelector::PseudoOutOfRange: 1134 if (!e )1135 return false; 1136 e ->document()->setContainsValidityStyleRules();1137 return e ->isOutOfRange();1160 if (!element) 1161 return false; 1162 element->document()->setContainsValidityStyleRules(); 1163 return element->isOutOfRange(); 1138 1164 case CSSSelector::PseudoUnknown: 1139 1165 case CSSSelector::PseudoNotParsed: … … 1144 1170 return false; 1145 1171 } 1146 if (sel ->m_match == CSSSelector::PseudoElement) {1147 if (! elementStyle && !m_isCollectingRulesOnly)1148 return false; 1149 1150 if (sel ->isUnknownPseudoElement()) {1172 if (selector->m_match == CSSSelector::PseudoElement) { 1173 if (!context.elementStyle && !m_isCollectingRulesOnly) 1174 return false; 1175 1176 if (selector->isUnknownPseudoElement()) { 1151 1177 m_hasUnknownPseudoElements = true; 1152 return e ->shadowPseudoId() == sel->value();1153 } 1154 1155 PseudoId pseudoId = CSSSelector::pseudoId(sel ->pseudoType());1178 return element->shadowPseudoId() == selector->value(); 1179 } 1180 1181 PseudoId pseudoId = CSSSelector::pseudoId(selector->pseudoType()); 1156 1182 if (pseudoId == FIRST_LETTER) { 1157 if (Document* document = e ->document())1183 if (Document* document = element->document()) 1158 1184 document->setUsesFirstLetterRules(true); 1159 1185 } -
trunk/Source/WebCore/css/SelectorChecker.h
r106833 r107197 52 52 enum SelectorMatch { SelectorMatches, SelectorFailsLocally, SelectorFailsAllSiblings, SelectorFailsCompletely }; 53 53 enum VisitedMatchType { VisitedMatchDisabled, VisitedMatchEnabled }; 54 55 struct SelectorCheckingContext { 56 // Initial selector constructor 57 SelectorCheckingContext(CSSSelector* selector, Element* element, VisitedMatchType visitedMatchType, RenderStyle* elementStyle = 0, RenderStyle* elementParentStyle = 0) 58 : selector(selector) 59 , element(element) 60 , visitedMatchType(visitedMatchType) 61 , elementStyle(elementStyle) 62 , elementParentStyle(elementParentStyle) 63 , isSubSelector(false) 64 { } 65 66 CSSSelector* selector; 67 Element* element; 68 VisitedMatchType visitedMatchType; 69 RenderStyle* elementStyle; 70 RenderStyle* elementParentStyle; 71 bool isSubSelector; 72 }; 73 54 74 bool checkSelector(CSSSelector*, Element*, bool isFastCheckableSelector = false) const; 55 SelectorMatch checkSelector( CSSSelector*, Element*, PseudoId& dynamicPseudo, bool isSubSelector, VisitedMatchType, RenderStyle* = 0, RenderStyle* elementParentStyle = 0) const;75 SelectorMatch checkSelector(const SelectorCheckingContext&, PseudoId&) const; 56 76 static bool isFastCheckableSelector(const CSSSelector*); 57 77 bool fastCheckSelector(const CSSSelector*, const Element*) const; … … 97 117 98 118 private: 99 bool checkOneSelector( CSSSelector*, Element*, PseudoId& dynamicPseudo, bool isSubSelector, VisitedMatchType, RenderStyle*, RenderStyle* elementParentStyle) const;119 bool checkOneSelector(const SelectorCheckingContext&, PseudoId&) const; 100 120 bool checkScrollbarPseudoClass(CSSSelector*, PseudoId& dynamicPseudo) const; 101 121 static bool isFrameFocused(const Element*);
Note: See TracChangeset
for help on using the changeset viewer.