Changeset 107197 in webkit


Ignore:
Timestamp:
Feb 9, 2012 1:36:24 AM (12 years ago)
Author:
rolandsteiner@chromium.org
Message:

2012-02-09 Roland Steiner <rolandsteiner@chromium.org>

SelectorChecker::checkSelector: move parameters into a struct
https://bugs.webkit.org/show_bug.cgi?id=77525

Added 'SelectorCheckingContext' struct to hold parameters for the function.
Adapted calling sites.

Reviewed by Antti Koivisto.

No new tests. (refactoring)

  • css/CSSStyleSelector.cpp: (WebCore::CSSStyleSelector::checkSelector):
  • css/SelectorChecker.cpp: (WebCore::SelectorChecker::checkSelector): (WebCore): (WebCore::SelectorChecker::checkOneSelector):
  • css/SelectorChecker.h: (SelectorCheckingContext): (WebCore::SelectorChecker::SelectorCheckingContext::SelectorCheckingContext): (SelectorChecker):
Location:
trunk/Source/WebCore
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r107196 r107197  
     12012-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
    1242012-02-09  Kent Tamura  <tkent@chromium.org>
    225
  • trunk/Source/WebCore/css/CSSStyleSelector.cpp

    r107193 r107197  
    20932093
    20942094    // 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);
    20962097    if (match != SelectorChecker::SelectorMatches)
    20972098        return false;
  • trunk/Source/WebCore/css/SelectorChecker.cpp

    r106833 r107197  
    269269bool SelectorChecker::checkSelector(CSSSelector* sel, Element* element, bool isFastCheckableSelector) const
    270270{
    271     PseudoId dynamicPseudo = NOPSEUDO;
    272271    if (isFastCheckableSelector && !element->isSVGElement()) {
    273272        if (!fastCheckRightmostSelector(sel, element, VisitedMatchDisabled))
     
    275274        return fastCheckSelector(sel, element);
    276275    }
    277     return checkSelector(sel, element, dynamicPseudo, false, VisitedMatchDisabled) == SelectorMatches;
     276
     277    PseudoId dynamicPseudo = NOPSEUDO;
     278    return checkSelector(SelectorCheckingContext(sel, element, SelectorChecker::VisitedMatchDisabled), dynamicPseudo) == SelectorMatches;
    278279}
    279280
     
    443444// * SelectorFailsAllSiblings - the selector fails for e and any sibling of e
    444445// * 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) const
     446SelectorChecker::SelectorMatch SelectorChecker::checkSelector(const SelectorCheckingContext& context, PseudoId& dynamicPseudo) const
    446447{
    447448#if ENABLE(SVG)
    448449    // Spec: CSS2 selectors cannot be applied to the (conceptually) cloned DOM tree
    449450    // because its contents are not part of the formal document structure.
    450     if (e->isSVGShadowRoot())
     451    if (context.element->isSVGShadowRoot())
    451452        return SelectorFailsCompletely;
    452453#endif
    453454
    454455    // first selector has to match
    455     if (!checkOneSelector(sel, e, dynamicPseudo, isSubSelector, visitedMatchType, elementStyle, elementParentStyle))
     456    if (!checkOneSelector(context, dynamicPseudo))
    456457        return SelectorFailsLocally;
    457458
    458459    // 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)
    464465        return SelectorMatches;
     466
     467    SelectorCheckingContext nextContext(context);
     468    nextContext.selector = historySelector;
    465469
    466470    if (relation != CSSSelector::SubSelector) {
     
    470474
    471475        // 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;
    474478    }
    475479
    476480    switch (relation) {
    477481    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);
    484488            if (match == SelectorMatches || match == SelectorFailsCompletely)
    485489                return match;
    486490        }
    487         break;
     491        return SelectorFailsCompletely;
     492
    488493    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
    496502    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
    508516    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();
    511519            if (parentStyle)
    512520                parentStyle->setChildrenAffectedByForwardPositionalRules();
    513521        }
    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);
    519528            if (match == SelectorMatches || match == SelectorFailsAllSiblings || match == SelectorFailsCompletely)
    520529                return match;
    521530        };
    522         break;
     531        return SelectorFailsAllSiblings;
     532
    523533    case CSSSelector::SubSelector:
    524534        // a selector is invalid if something follows a pseudo-element
    525535        // We make an exception for scrollbar pseudo elements and allow a set of pseudo classes (but nothing else)
    526536        // to follow the pseudo elements.
    527         if ((elementStyle || m_isCollectingRulesOnly) && dynamicPseudo != NOPSEUDO && dynamicPseudo != SELECTION
    528              && !((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))
    529539            return SelectorFailsCompletely;
    530         return checkSelector(sel, e, dynamicPseudo, true, visitedMatchType, elementStyle, elementParentStyle);
     540        nextContext.isSubSelector = true;
     541        return checkSelector(nextContext, dynamicPseudo);
     542
    531543    case CSSSelector::ShadowDescendant:
    532544        {
    533             Node* shadowHostNode = e->shadowAncestorNode();
    534             if (shadowHostNode == e || !shadowHostNode->isElementNode())
     545            Node* shadowHostNode = context.element->shadowAncestorNode();
     546            if (shadowHostNode == context.element || !shadowHostNode->isElementNode())
    535547                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();
    541557    return SelectorFailsCompletely;
    542558}
     
    688704}
    689705
    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))
     706bool 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))
    694714        return false;
    695715
    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())
    706726            return false;
    707727
    708728        bool caseSensitive = !m_documentIsHTML || !htmlAttributeHasCaseInsensitiveValue(attr);
    709729
    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) {
    715735        // 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()) {
    719741                // :not cannot nest. I don't really know why this is a
    720742                // restriction in CSS3, but it is, so let's honor it.
    721743                // the parser enforces that this never occurs
    722                 ASSERT(subSel->pseudoType() != CSSSelector::PseudoNot);
     744                ASSERT(subContext.selector->pseudoType() != CSSSelector::PseudoNot);
    723745                // We select between :visited and :link when applying. We don't know which one applied (or not) yet.
    724                 if (subSel->pseudoType() == CSSSelector::PseudoVisited || (subSel->pseudoType() == CSSSelector::PseudoLink && visitedMatchType == VisitedMatchEnabled))
     746                if (subContext.selector->pseudoType() == CSSSelector::PseudoVisited || (subContext.selector->pseudoType() == CSSSelector::PseudoLink && subContext.visitedMatchType == VisitedMatchEnabled))
    725747                    return true;
    726                 if (!checkOneSelector(subSel, e, dynamicPseudo, true, visitedMatchType, elementStyle, elementParentStyle))
     748                if (!checkOneSelector(subContext, dynamicPseudo))
    727749                    return true;
    728750            }
     
    730752            // CSS scrollbars match a specific subset of pseudo classes, and they have specialized rules for each
    731753            // (since there are no elements involved).
    732             return checkScrollbarPseudoClass(sel, dynamicPseudo);
     754            return checkScrollbarPseudoClass(selector, dynamicPseudo);
    733755        } else if (dynamicPseudo == SELECTION) {
    734             if (sel->pseudoType() == CSSSelector::PseudoWindowInactive)
     756            if (selector->pseudoType() == CSSSelector::PseudoWindowInactive)
    735757                return !m_document->page()->focusController()->isActive();
    736758        }
    737759
    738760        // Normal element pseudo class checking.
    739         switch (sel->pseudoType()) {
     761        switch (selector->pseudoType()) {
    740762            // Pseudo classes:
    741763        case CSSSelector::PseudoNot:
     
    744766            {
    745767                bool result = true;
    746                 for (Node* n = e->firstChild(); n; n = n->nextSibling()) {
     768                for (Node* n = element->firstChild(); n; n = n->nextSibling()) {
    747769                    if (n->isElementNode()) {
    748770                        result = false;
     
    758780                }
    759781                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);
    764786                }
    765787                return result;
     
    767789        case CSSSelector::PseudoFirstChild:
    768790            // first-child matches the first child that is an element
    769             if (e->parentElement()) {
     791            if (element->parentElement()) {
    770792                bool result = false;
    771                 if (!e->previousElementSibling())
     793                if (!element->previousElementSibling())
    772794                    result = true;
    773795                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();
    776798                    if (parentStyle)
    777799                        parentStyle->setChildrenAffectedByFirstChildRules();
     
    784806        case CSSSelector::PseudoFirstOfType:
    785807            // first-of-type matches the first element of its type
    786             if (e->parentElement()) {
     808            if (element->parentElement()) {
    787809                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()) {
    790812                    if (sibling->hasTagName(type)) {
    791813                        result = false;
     
    794816                }
    795817                if (!m_isCollectingRulesOnly) {
    796                     RenderStyle* parentStyle = elementStyle ? elementParentStyle : e->parentNode()->renderStyle();
     818                    RenderStyle* parentStyle = context.elementStyle ? context.elementParentStyle : element->parentNode()->renderStyle();
    797819                    if (parentStyle)
    798820                        parentStyle->setChildrenAffectedByForwardPositionalRules();
     
    803825        case CSSSelector::PseudoLastChild:
    804826            // 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();
    807829                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();
    810832                    if (parentStyle)
    811833                        parentStyle->setChildrenAffectedByLastChildRules();
     
    818840        case CSSSelector::PseudoLastOfType:
    819841            // last-of-type matches the last element of its type
    820             if (Element* parentElement = e->parentElement()) {
     842            if (Element* parentElement = element->parentElement()) {
    821843                if (!m_isCollectingRulesOnly) {
    822                     RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentElement->renderStyle();
     844                    RenderStyle* parentStyle = context.elementStyle ? context.elementParentStyle : parentElement->renderStyle();
    823845                    if (parentStyle)
    824846                        parentStyle->setChildrenAffectedByBackwardPositionalRules();
     
    826848                if (!parentElement->isFinishedParsingChildren())
    827849                    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()) {
    830852                    if (sibling->hasTagName(type))
    831853                        return false;
     
    835857            break;
    836858        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();
    840862
    841863                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();
    844866                    if (parentStyle) {
    845867                        parentStyle->setChildrenAffectedByFirstChildRules();
     
    856878        case CSSSelector::PseudoOnlyOfType:
    857879            // FIXME: This selector is very slow.
    858             if (Element* parentElement = e->parentElement()) {
     880            if (Element* parentElement = element->parentElement()) {
    859881                if (!m_isCollectingRulesOnly) {
    860                     RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentElement->renderStyle();
     882                    RenderStyle* parentStyle = context.elementStyle ? context.elementParentStyle : parentElement->renderStyle();
    861883                    if (parentStyle) {
    862884                        parentStyle->setChildrenAffectedByForwardPositionalRules();
     
    866888                if (!parentElement->isFinishedParsingChildren())
    867889                    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()) {
    870892                    if (sibling->hasTagName(type))
    871893                        return false;
    872894                }
    873                 for (const Element* sibling = e->nextElementSibling(); sibling; sibling = sibling->nextElementSibling()) {
     895                for (const Element* sibling = element->nextElementSibling(); sibling; sibling = sibling->nextElementSibling()) {
    874896                    if (sibling->hasTagName(type))
    875897                        return false;
     
    879901            break;
    880902        case CSSSelector::PseudoNthChild:
    881             if (!sel->parseNth())
     903            if (!selector->parseNth())
    882904                break;
    883             if (Element* parentElement = e->parentElement()) {
     905            if (Element* parentElement = element->parentElement()) {
    884906                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()) {
    886908                    RenderStyle* s = sibling->renderStyle();
    887909                    unsigned index = s ? s->childIndex() : 0;
     
    894916
    895917                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();
    898920                    if (childStyle)
    899921                        childStyle->setChildIndex(count);
     
    902924                }
    903925
    904                 if (sel->matchNth(count))
     926                if (selector->matchNth(count))
    905927                    return true;
    906928            }
    907929            break;
    908930        case CSSSelector::PseudoNthOfType:
    909             if (!sel->parseNth())
     931            if (!selector->parseNth())
    910932                break;
    911             if (Element* parentElement = e->parentElement()) {
     933            if (Element* parentElement = element->parentElement()) {
    912934                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()) {
    915937                    if (sibling->hasTagName(type))
    916938                        ++count;
    917939                }
    918940                if (!m_isCollectingRulesOnly) {
    919                     RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentElement->renderStyle();
     941                    RenderStyle* parentStyle = context.elementStyle ? context.elementParentStyle : parentElement->renderStyle();
    920942                    if (parentStyle)
    921943                        parentStyle->setChildrenAffectedByForwardPositionalRules();
    922944                }
    923945
    924                 if (sel->matchNth(count))
     946                if (selector->matchNth(count))
    925947                    return true;
    926948            }
    927949            break;
    928950        case CSSSelector::PseudoNthLastChild:
    929             if (!sel->parseNth())
     951            if (!selector->parseNth())
    930952                break;
    931             if (Element* parentElement = e->parentElement()) {
     953            if (Element* parentElement = element->parentElement()) {
    932954                if (!m_isCollectingRulesOnly) {
    933                     RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentElement->renderStyle();
     955                    RenderStyle* parentStyle = context.elementStyle ? context.elementParentStyle : parentElement->renderStyle();
    934956                    if (parentStyle)
    935957                        parentStyle->setChildrenAffectedByBackwardPositionalRules();
     
    938960                    return false;
    939961                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())
    941963                    ++count;
    942                 if (sel->matchNth(count))
     964                if (selector->matchNth(count))
    943965                    return true;
    944966            }
    945967            break;
    946968        case CSSSelector::PseudoNthLastOfType:
    947             if (!sel->parseNth())
     969            if (!selector->parseNth())
    948970                break;
    949             if (Element* parentElement = e->parentElement()) {
     971            if (Element* parentElement = element->parentElement()) {
    950972                if (!m_isCollectingRulesOnly) {
    951                     RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentElement->renderStyle();
     973                    RenderStyle* parentStyle = context.elementStyle ? context.elementParentStyle : parentElement->renderStyle();
    952974                    if (parentStyle)
    953975                        parentStyle->setChildrenAffectedByBackwardPositionalRules();
     
    956978                    return false;
    957979                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()) {
    960982                    if (sibling->hasTagName(type))
    961983                        ++count;
    962984                }
    963                 if (sel->matchNth(count))
     985                if (selector->matchNth(count))
    964986                    return true;
    965987            }
    966988            break;
    967989        case CSSSelector::PseudoTarget:
    968             if (e == e->document()->cssTarget())
     990            if (element == element->document()->cssTarget())
    969991                return true;
    970992            break;
    971993        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                }
    9751001            }
    9761002            break;
    9771003        case CSSSelector::PseudoAutofill:
    978             if (!e || !e->isFormControlElement())
     1004            if (!element || !element->isFormControlElement())
    9791005                break;
    980             if (HTMLInputElement* inputElement = e->toInputElement())
     1006            if (HTMLInputElement* inputElement = element->toInputElement())
    9811007                return inputElement->isAutofilled();
    9821008            break;
     
    9841010        case CSSSelector::PseudoLink:
    9851011            // :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();
    9871013        case CSSSelector::PseudoVisited:
    9881014            // ...except if :visited matching is disabled for ancestor/sibling matching.
    989             return e->isLink() && visitedMatchType == VisitedMatchEnabled;
     1015            return element->isLink() && context.visitedMatchType == VisitedMatchEnabled;
    9901016        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())
    9961022                return true;
    9971023            break;
    9981024        case CSSSelector::PseudoFocus:
    999             return matchesFocusPseudoClass(e);
     1025            return matchesFocusPseudoClass(element);
    10001026        case CSSSelector::PseudoHover:
    10011027            // If we're in quirks mode, then hover should never match anchors with no
    10021028            // 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))
    10091035                    return true;
    10101036            }
     
    10131039            // If we're in quirks mode, then :active should never match anchors with no
    10141040            // 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))
    10211047                    return true;
    10221048            }
    10231049            break;
    10241050        case CSSSelector::PseudoEnabled:
    1025             if (e && e->isFormControlElement())
    1026                 return e->isEnabledFormControl();
     1051            if (element && element->isFormControlElement())
     1052                return element->isEnabledFormControl();
    10271053            break;
    10281054        case CSSSelector::PseudoFullPageMedia:
    1029             return e && e->document() && e->document()->isMediaDocument();
     1055            return element && element->document() && element->document()->isMediaDocument();
    10301056            break;
    10311057        case CSSSelector::PseudoDefault:
    1032             return e && e->isDefaultButtonForForm();
     1058            return element && element->isDefaultButtonForForm();
    10331059        case CSSSelector::PseudoDisabled:
    1034             if (e && e->isFormControlElement())
    1035                 return !e->isEnabledFormControl();
     1060            if (element && element->isFormControlElement())
     1061                return !element->isEnabledFormControl();
    10361062            break;
    10371063        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();
    10411067        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();
    10451071        case CSSSelector::PseudoOptional:
    1046             return e && e->isOptionalFormControl();
     1072            return element && element->isOptionalFormControl();
    10471073        case CSSSelector::PseudoRequired:
    1048             return e && e->isRequiredFormControl();
     1074            return element && element->isRequiredFormControl();
    10491075        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();
    10541080        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();
    10591085        case CSSSelector::PseudoChecked:
    10601086            {
    1061                 if (!e || !e->isFormControlElement())
     1087                if (!element || !element->isFormControlElement())
    10621088                    break;
    10631089                // Even though WinIE allows checked and indeterminate to co-exist, the CSS selector spec says that
    10641090                // you can't be both checked and indeterminate. We will behave like WinIE behind the scenes and just
    10651091                // obey the CSS spec here in the test for matching the pseudo.
    1066                 HTMLInputElement* inputElement = e->toInputElement();
     1092                HTMLInputElement* inputElement = element->toInputElement();
    10671093                if (inputElement && inputElement->shouldAppearChecked() && !inputElement->isIndeterminate())
    10681094                    return true;
    1069                 if (e->hasTagName(optionTag) && toHTMLOptionElement(e)->selected())
     1095                if (element->hasTagName(optionTag) && toHTMLOptionElement(element)->selected())
    10701096                    return true;
    10711097                break;
     
    10731099        case CSSSelector::PseudoIndeterminate:
    10741100            {
    1075                 if (!e || !e->isFormControlElement())
     1101                if (!element || !element->isFormControlElement())
    10761102                    break;
    10771103#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);
    10801106                    if (progress && !progress->isDeterminate())
    10811107                        return true;
     
    10831109                }
    10841110#endif
    1085                 HTMLInputElement* inputElement = e->toInputElement();
     1111                HTMLInputElement* inputElement = element->toInputElement();
    10861112                if (inputElement && inputElement->isIndeterminate())
    10871113                    return true;
     
    10891115            }
    10901116        case CSSSelector::PseudoRoot:
    1091             if (e == e->document()->documentElement())
     1117            if (element == element->document()->documentElement())
    10921118                return true;
    10931119            break;
    10941120        case CSSSelector::PseudoLang:
    10951121            {
    1096                 AtomicString value = e->computeInheritedLanguage();
    1097                 const AtomicString& argument = sel->argument();
     1122                AtomicString value = element->computeInheritedLanguage();
     1123                const AtomicString& argument = selector->argument();
    10981124                if (value.isEmpty() || !value.startsWith(argument, false))
    10991125                    break;
     
    11081134            // that element. Also, an <iframe>, <object> or <embed> element whose child browsing
    11091135            // 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())
    11111137                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();
    11151141        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();
    11191145        case CSSSelector::PseudoFullScreenAncestor:
    1120             return e->containsFullScreenElement();
     1146            return element->containsFullScreenElement();
    11211147        case CSSSelector::PseudoFullScreenDocument:
    11221148            // While a Document is in the fullscreen state, the 'full-screen-document' pseudoclass applies
    11231149            // to all elements of that Document.
    1124             if (!e->document()->webkitIsFullScreen())
     1150            if (!element->document()->webkitIsFullScreen())
    11251151                return false;
    11261152            return true;
    11271153#endif
    11281154        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();
    11331159        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();
    11381164        case CSSSelector::PseudoUnknown:
    11391165        case CSSSelector::PseudoNotParsed:
     
    11441170        return false;
    11451171    }
    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()) {
    11511177            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());
    11561182        if (pseudoId == FIRST_LETTER) {
    1157             if (Document* document = e->document())
     1183            if (Document* document = element->document())
    11581184                document->setUsesFirstLetterRules(true);
    11591185        }
  • trunk/Source/WebCore/css/SelectorChecker.h

    r106833 r107197  
    5252    enum SelectorMatch { SelectorMatches, SelectorFailsLocally, SelectorFailsAllSiblings, SelectorFailsCompletely };
    5353    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
    5474    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;
    5676    static bool isFastCheckableSelector(const CSSSelector*);
    5777    bool fastCheckSelector(const CSSSelector*, const Element*) const;
     
    97117
    98118private:
    99     bool checkOneSelector(CSSSelector*, Element*, PseudoId& dynamicPseudo, bool isSubSelector, VisitedMatchType, RenderStyle*, RenderStyle* elementParentStyle) const;
     119    bool checkOneSelector(const SelectorCheckingContext&, PseudoId&) const;
    100120    bool checkScrollbarPseudoClass(CSSSelector*, PseudoId& dynamicPseudo) const;
    101121    static bool isFrameFocused(const Element*);
Note: See TracChangeset for help on using the changeset viewer.