Changeset 107212 in webkit


Ignore:
Timestamp:
Feb 9, 2012 3:44:28 AM (12 years ago)
Author:
rolandsteiner@chromium.org
Message:

Fix mirroring with SVG fonts
https://bugs.webkit.org/show_bug.cgi?id=77067

Patch by Philip Rogers <pdr@google.com> on 2012-02-09
Reviewed by Nikolas Zimmermann.

SVG fonts were incorrectly handling mirrored characters in bidi text.
In this change I added the function createStringWithMirroredCharacters
which handles mirroring the characters when selecting glyphs for SVG
fonts. I also made a small cosmetic change in the function
charactersWithArabicForm, changing the bool parameter "mirror" to "rtl"
which better reflects what it actually does.

Several new tests were added to test mirroring with SVG fonts in the
presence of Arabic forms and non-BMP characters.

Tests: svg/custom/glyph-selection-arabic-forms.svg

svg/custom/glyph-selection-bidi-mirror.svg
svg/custom/glyph-selection-non-bmp.svg

  • platform/graphics/SVGGlyph.cpp:

(WebCore::charactersWithArabicForm):

  • svg/SVGFontData.cpp:

(WebCore::SVGFontData::applySVGGlyphSelection):
(WebCore::SVGFontData::createStringWithMirroredCharacters):

  • svg/SVGFontData.h:

(SVGFontData):

Location:
trunk/Source/WebCore
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r107211 r107212  
    6161        * dom/ExceptionCodePlaceholder.h:
    6262        (NoExceptionAssertionChecker):
     63
     642012-02-09  Roland Steiner  <rolandsteiner@chromium.org>
     65
     66        SelectorChecker::checkSelector: move parameters into a struct
     67        https://bugs.webkit.org/show_bug.cgi?id=77525
     68
     69        Added 'SelectorCheckingContext' struct to hold parameters for the function.
     70        Adapted calling sites.
     71
     72        Reviewed by Antti Koivisto.
     73
     74        No new tests. (refactoring)
     75
     76        * css/CSSStyleSelector.cpp:
     77        (WebCore::CSSStyleSelector::checkSelector):
     78        * css/SelectorChecker.cpp:
     79        (WebCore::SelectorChecker::checkSelector):
     80        (WebCore):
     81        (WebCore::SelectorChecker::checkOneSelector):
     82        * css/SelectorChecker.h:
     83        (SelectorCheckingContext):
     84        (WebCore::SelectorChecker::SelectorCheckingContext::SelectorCheckingContext):
     85        (SelectorChecker):
    6386
    64872012-02-09  Roland Steiner  <rolandsteiner@chromium.org>
  • trunk/Source/WebCore/css/CSSStyleSelector.cpp

    r107205 r107212  
    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

    r107205 r107212  
    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) && nextContext.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

    r107205 r107212  
    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.