Changeset 140371 in webkit


Ignore:
Timestamp:
Jan 21, 2013 4:45:14 PM (11 years ago)
Author:
akling@apple.com
Message:

CSS: Make tag sub-selectors standalone CSSSelectors.
<http://webkit.org/b/107111>

Reviewed by Antti Koivisto.

TL;DR: Instead of storing a QualifiedName with every CSSSelector, special-case tag selectors

by promoting them to stand-alone CSSSelectors.
33% reduction in CSS selector memory usage, 4.77 MB progression on Membuster3.
Fixed some bugs in Shadow DOM that were exposed by these changes.

A selector like this:

div.tripp.trapp#trull { }

Would previously be represented by a chain of 3 CSSSelector objects like so:

[ Tag: "div", Type: Class, Value: "tripp" ]
[ Tag: *, Type: Class, Value: "trapp" ]
[ Tag: *, Type: ID, Value: "trull" ]

After this change, the memory layout becomes:

[ Type: Tag, Value: "div" ]
[ Type: Class, Value: "tripp" ]
[ Type: Class, Value: "trapp" ]
[ Type: ID, Value: "trull" ]

This is a huge net memory win since the majority of selectors don't even have a tag name
and those that do now have a flat cost of one more CSSSelector.
Traversal is also slightly cleaner since any tag name will now be in a predictable place.

  • css/SelectorChecker.cpp:

(WebCore::isFastCheckableMatch):

  • html/shadow/HTMLContentElement.cpp:

(WebCore::validateSubSelector):

Renamed CSSSelector::None to CSSSelector::Tag.

  • css/SelectorChecker.h:

(WebCore::SelectorChecker::tagMatches):

  • css/StyleResolver.cpp:

(WebCore::StyleResolver::ruleMatches):

Changed SelectorChecker::tagMatches() to take a QualifiedName instead of a CSSSelector.

  • dom/QualifiedName.cpp:

(WebCore::QualifiedName::deref):
(WebCore::QualifiedName::QualifiedNameImpl::~QualifiedNameImpl):

  • dom/QualifiedName.h:

(QualifiedNameImpl):

Give QualifiedNameImpl a destructor so it can remove itself from the global cache instead of
having QualifiedName do it. This makes it possible to participate in ownership of QualifiedNames
via a QualifiedNameImpl pointer, as used by the union member in CSSSelector.

  • css/CSSGrammar.y.in:
  • css/CSSParser.cpp:

(WebCore::CSSParser::createFloatingSelectorWithTagName):
(WebCore::CSSParser::updateSpecifiersWithNamespaceIfNeeded):
(WebCore::CSSParser::updateSpecifiersWithElementName):

  • css/CSSParser.h:
  • css/CSSParserValues.h:

(CSSParserSelector):

  • css/CSSParserValues.cpp:

(WebCore::CSSParserSelector::CSSParserSelector):
(WebCore::CSSParserSelector::prependTagSelector):

Make the CSS parser slap a CSSSelector with m_match=Tag at the head of all selectors that match
one or more of these criteria:

  • The selector starts with a tag, e.g "div.foo" or just plain "span"
  • There is a @namespace rule in effect, and the override namespace needs to be stored with the selector. These will have CSSSelectors::m_isTagForNamespaceRule set, this is only so that selector serialization can avoid outputting a '*' tag where we previously didn't.

(WebCore::CSSParserSelector::isSimple):

Merged the CSSSelector::isSimple() logic into CSSParserSelector, since it's only needed during parsing
to figure out if a selector is allowed within :not().

  • css/CSSSelector.h:

(CSSSelector):
(WebCore::CSSSelector::setValue):
(WebCore::CSSSelector::CSSSelector):
(WebCore::CSSSelector::~CSSSelector):
(WebCore::CSSSelector::tagQName):

  • css/CSSSelector.cpp:

(WebCore::CSSSelector::createRareData):
(WebCore::CSSSelector::operator==):

Add a QualifiedNameImpl* m_tagQName member to the CSSSelector data union. This union pointer is used
if m_match == Tag. tagQName() is used to retrieve the tag (renamed from tag().)

(WebCore::CSSSelector::selectorText):

Only serialize Tag selector components that aren't namespace placeholders. This behavior is web-facing
so we make an effort to stay consistent.

(WebCore::CSSSelector::specificityForOneSelector):
(WebCore::CSSSelector::specificityForPage):

  • css/CSSSelectorList.cpp:

(WebCore::SelectorNeedsNamespaceResolutionFunctor::operator()):

  • css/RuleSet.cpp:

(WebCore::isSelectorMatchingHTMLBasedOnRuleHash):

  • css/SelectorFilter.cpp:

(WebCore::collectDescendantSelectorIdentifierHashes):
(WebCore::SelectorFilter::collectIdentifierHashes):

Adapt algorithms to having Tag selectors.

(WebCore::selectorListContainsUncommonAttributeSelector):

Loop through all selector components when looking for uncommon attributes.

(WebCore::determinePropertyWhitelistType):

Loop through all selector components when looking for ::cue().

(WebCore::RuleSet::addRule):
(WebCore::RuleSet::findBestRuleSetAndAdd):

Break addRule into two methods to be able to peek ahead if the first selector is a Tag.
Otherwise we'd end up sticking most selectors in m_tagRules, breaking the class/ID/etc optimizations.

  • css/SelectorChecker.cpp:

(WebCore::SelectorChecker::fastCheck):
(WebCore::SelectorChecker::fastCheckSingleSelector):

It's no longer necessary to check the tagQName for every selector component, so don't.
Also simplified the signature of the template argument function.

(WebCore::SelectorChecker::fastCheckRightmostSelector):

Updated for Tag selectors.

(WebCore::SelectorChecker::checkOne):
(WebCore::SelectorChecker::matches):
(WebCore::SelectorChecker::match):

Have match() take a SiblingTraversalStrategy so it can forward that to checkOne().
This is necessary for shadow DOM code that was incorrectly calling checkOne() instead of match().

  • css/StyleResolver.cpp:

(WebCore::StyleResolver::ruleMatches):

The meaning of "single-part selector" changes a bit with this patch, and no longer includes "div.foo"
as that is now a Tag, followed by a Class. Given that, we can't assume the tag check is unnecessary
just because the rightmost descendant was found in one of the hashes.

(WebCore::StyleResolver::matchPageRulesForList):

Loop through all selector components when matching @page since pseudo types may not always be in
the first subselector now.

  • html/shadow/ContentDistributor.cpp:

(WebCore::ContentDistributor::collectSelectFeatureSetFrom):

Collect feature information from subselectors to make sure nothing is missed. (This bug was exposed
by offsetting the subselectors.)

  • html/shadow/ContentSelectorQuery.cpp:

(WebCore::ContentSelectorChecker::checkContentSelector):

Call SelectorChecker::match() instead of checkOne() to make subselector traversal work properly.

Location:
trunk/Source/WebCore
Files:
20 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r140370 r140371  
     12013-01-21  Andreas Kling  <akling@apple.com>
     2
     3        CSS: Make tag sub-selectors standalone CSSSelectors.
     4        <http://webkit.org/b/107111>
     5
     6        Reviewed by Antti Koivisto.
     7
     8        TL;DR: Instead of storing a QualifiedName with every CSSSelector, special-case tag selectors
     9               by promoting them to stand-alone CSSSelectors.
     10               33% reduction in CSS selector memory usage, 4.77 MB progression on Membuster3.
     11               Fixed some bugs in Shadow DOM that were exposed by these changes.
     12
     13        A selector like this:
     14
     15            div.tripp.trapp#trull { }
     16
     17        Would previously be represented by a chain of 3 CSSSelector objects like so:
     18
     19            [ Tag: "div",  Type: Class,  Value: "tripp" ]
     20            [ Tag:     *,  Type: Class,  Value: "trapp" ]
     21            [ Tag:     *,  Type: ID,     Value: "trull" ]
     22
     23        After this change, the memory layout becomes:
     24
     25            [ Type: Tag,    Value: "div"   ]
     26            [ Type: Class,  Value: "tripp" ]
     27            [ Type: Class,  Value: "trapp" ]
     28            [ Type: ID,     Value: "trull" ]
     29
     30        This is a huge net memory win since the majority of selectors don't even have a tag name
     31        and those that do now have a flat cost of one more CSSSelector.
     32        Traversal is also slightly cleaner since any tag name will now be in a predictable place.
     33
     34        * css/SelectorChecker.cpp:
     35        (WebCore::isFastCheckableMatch):
     36        * html/shadow/HTMLContentElement.cpp:
     37        (WebCore::validateSubSelector):
     38
     39            Renamed CSSSelector::None to CSSSelector::Tag.
     40
     41        * css/SelectorChecker.h:
     42        (WebCore::SelectorChecker::tagMatches):
     43        * css/StyleResolver.cpp:
     44        (WebCore::StyleResolver::ruleMatches):
     45
     46            Changed SelectorChecker::tagMatches() to take a QualifiedName instead of a CSSSelector.
     47
     48        * dom/QualifiedName.cpp:
     49        (WebCore::QualifiedName::deref):
     50        (WebCore::QualifiedName::QualifiedNameImpl::~QualifiedNameImpl):
     51        * dom/QualifiedName.h:
     52        (QualifiedNameImpl):
     53
     54            Give QualifiedNameImpl a destructor so it can remove itself from the global cache instead of
     55            having QualifiedName do it. This makes it possible to participate in ownership of QualifiedNames
     56            via a QualifiedNameImpl pointer, as used by the union member in CSSSelector.
     57
     58        * css/CSSGrammar.y.in:
     59        * css/CSSParser.cpp:
     60        (WebCore::CSSParser::createFloatingSelectorWithTagName):
     61        (WebCore::CSSParser::updateSpecifiersWithNamespaceIfNeeded):
     62        (WebCore::CSSParser::updateSpecifiersWithElementName):
     63        * css/CSSParser.h:
     64        * css/CSSParserValues.h:
     65        (CSSParserSelector):
     66        * css/CSSParserValues.cpp:
     67        (WebCore::CSSParserSelector::CSSParserSelector):
     68        (WebCore::CSSParserSelector::prependTagSelector):
     69
     70            Make the CSS parser slap a CSSSelector with m_match=Tag at the head of all selectors that match
     71            one or more of these criteria:
     72
     73            - The selector starts with a tag, e.g "div.foo" or just plain "span"
     74            - There is a @namespace rule in effect, and the override namespace needs to be stored with the selector.
     75              These will have CSSSelectors::m_isTagForNamespaceRule set, this is only so that selector serialization
     76              can avoid outputting a '*' tag where we previously didn't.
     77
     78        (WebCore::CSSParserSelector::isSimple):
     79
     80            Merged the CSSSelector::isSimple() logic into CSSParserSelector, since it's only needed during parsing
     81            to figure out if a selector is allowed within :not().
     82
     83        * css/CSSSelector.h:
     84        (CSSSelector):
     85        (WebCore::CSSSelector::setValue):
     86        (WebCore::CSSSelector::CSSSelector):
     87        (WebCore::CSSSelector::~CSSSelector):
     88        (WebCore::CSSSelector::tagQName):
     89        * css/CSSSelector.cpp:
     90        (WebCore::CSSSelector::createRareData):
     91        (WebCore::CSSSelector::operator==):
     92
     93            Add a QualifiedNameImpl* m_tagQName member to the CSSSelector data union. This union pointer is used
     94            if m_match == Tag. tagQName() is used to retrieve the tag (renamed from tag().)
     95
     96        (WebCore::CSSSelector::selectorText):
     97
     98            Only serialize Tag selector components that aren't namespace placeholders. This behavior is web-facing
     99            so we make an effort to stay consistent.
     100
     101        (WebCore::CSSSelector::specificityForOneSelector):
     102        (WebCore::CSSSelector::specificityForPage):
     103        * css/CSSSelectorList.cpp:
     104        (WebCore::SelectorNeedsNamespaceResolutionFunctor::operator()):
     105        * css/RuleSet.cpp:
     106        (WebCore::isSelectorMatchingHTMLBasedOnRuleHash):
     107        * css/SelectorFilter.cpp:
     108        (WebCore::collectDescendantSelectorIdentifierHashes):
     109        (WebCore::SelectorFilter::collectIdentifierHashes):
     110
     111            Adapt algorithms to having Tag selectors.
     112
     113        (WebCore::selectorListContainsUncommonAttributeSelector):
     114
     115            Loop through all selector components when looking for uncommon attributes.
     116
     117        (WebCore::determinePropertyWhitelistType):
     118
     119            Loop through all selector components when looking for ::cue().
     120
     121        (WebCore::RuleSet::addRule):
     122        (WebCore::RuleSet::findBestRuleSetAndAdd):
     123
     124            Break addRule into two methods to be able to peek ahead if the first selector is a Tag.
     125            Otherwise we'd end up sticking most selectors in m_tagRules, breaking the class/ID/etc optimizations.
     126
     127        * css/SelectorChecker.cpp:
     128        (WebCore::SelectorChecker::fastCheck):
     129        (WebCore::SelectorChecker::fastCheckSingleSelector):
     130
     131            It's no longer necessary to check the tagQName for every selector component, so don't.
     132            Also simplified the signature of the template argument function.
     133
     134        (WebCore::SelectorChecker::fastCheckRightmostSelector):
     135
     136            Updated for Tag selectors.
     137
     138        (WebCore::SelectorChecker::checkOne):
     139        (WebCore::SelectorChecker::matches):
     140        (WebCore::SelectorChecker::match):
     141
     142            Have match() take a SiblingTraversalStrategy so it can forward that to checkOne().
     143            This is necessary for shadow DOM code that was incorrectly calling checkOne() instead of match().
     144
     145        * css/StyleResolver.cpp:
     146        (WebCore::StyleResolver::ruleMatches):
     147
     148            The meaning of "single-part selector" changes a bit with this patch, and no longer includes "div.foo"
     149            as that is now a Tag, followed by a Class. Given that, we can't assume the tag check is unnecessary
     150            just because the rightmost descendant was found in one of the hashes.
     151
     152        (WebCore::StyleResolver::matchPageRulesForList):
     153
     154            Loop through all selector components when matching @page since pseudo types may not always be in
     155            the first subselector now.
     156
     157        * html/shadow/ContentDistributor.cpp:
     158        (WebCore::ContentDistributor::collectSelectFeatureSetFrom):
     159
     160            Collect feature information from subselectors to make sure nothing is missed. (This bug was exposed
     161            by offsetting the subselectors.)
     162
     163        * html/shadow/ContentSelectorQuery.cpp:
     164        (WebCore::ContentSelectorChecker::checkContentSelector):
     165
     166            Call SelectorChecker::match() instead of checkOne() to make subselector traversal work properly.
     167
    11682013-01-21  Levi Weintraub  <leviw@chromium.org>
    2169
  • trunk/Source/WebCore/css/CSSGrammar.y.in

    r139866 r140371  
    841841page_selector:
    842842    IDENT {
    843         $$ = parser->createFloatingSelector();
    844         $$->setTag(QualifiedName(nullAtom, $1, parser->m_defaultNamespace));
     843        $$ = parser->createFloatingSelectorWithTagName(QualifiedName(nullAtom, $1, parser->m_defaultNamespace));
    845844        $$->setForPage();
    846845    }
     
    848847        $$ = $2;
    849848        if ($$) {
    850             $$->setTag(QualifiedName(nullAtom, $1, parser->m_defaultNamespace));
     849            $$->prependTagSelector(QualifiedName(nullAtom, $1, parser->m_defaultNamespace));
    851850            $$->setForPage();
    852851        }
     
    11481147simple_selector:
    11491148    element_name {
    1150         $$ = parser->createFloatingSelector();
    1151         $$->setTag(QualifiedName(nullAtom, $1, parser->m_defaultNamespace));
     1149        $$ = parser->createFloatingSelectorWithTagName(QualifiedName(nullAtom, $1, parser->m_defaultNamespace));
    11521150    }
    11531151    | element_name specifier_list {
     
    11591157        $$ = $1;
    11601158        if ($$)
    1161             parser->updateSpecifiersWithElementName(nullAtom, starAtom, $$);
     1159            parser->updateSpecifiersWithNamespaceIfNeeded($$);
    11621160    }
    11631161    | namespace_selector element_name {
    1164         $$ = parser->createFloatingSelector();
    1165         $$->setTag(parser->determineNameInNamespace($1, $2));
     1162        $$ = parser->createFloatingSelectorWithTagName(parser->determineNameInNamespace($1, $2));
    11661163    }
    11671164    | namespace_selector element_name specifier_list {
  • trunk/Source/WebCore/css/CSSParser.cpp

    r140300 r140371  
    1054910549}
    1055010550
     10551CSSParserSelector* CSSParser::createFloatingSelectorWithTagName(const QualifiedName& tagQName)
     10552{
     10553    CSSParserSelector* selector = new CSSParserSelector(tagQName);
     10554    m_floatingSelectors.add(selector);
     10555    return selector;
     10556}
     10557
    1055110558CSSParserSelector* CSSParser::createFloatingSelector()
    1055210559{
     
    1090410911}
    1090510912
    10906 void CSSParser::updateSpecifiersWithElementName(const AtomicString& namespacePrefix, const AtomicString& elementName, CSSParserSelector* specifiers)
     10913void CSSParser::updateSpecifiersWithNamespaceIfNeeded(CSSParserSelector* specifiers)
     10914{
     10915    if (m_defaultNamespace != starAtom || specifiers->isCustomPseudoElement())
     10916        updateSpecifiersWithElementName(nullAtom, starAtom, specifiers, /*tagIsForNamespaceRule*/true);
     10917}
     10918
     10919void CSSParser::updateSpecifiersWithElementName(const AtomicString& namespacePrefix, const AtomicString& elementName, CSSParserSelector* specifiers, bool tagIsForNamespaceRule)
    1090710920{
    1090810921    AtomicString determinedNamespace = namespacePrefix != nullAtom && m_styleSheet ? m_styleSheet->determineNamespace(namespacePrefix) : m_defaultNamespace;
    10909     QualifiedName tag = QualifiedName(namespacePrefix, elementName, determinedNamespace);
     10922    QualifiedName tag(namespacePrefix, elementName, determinedNamespace);
     10923
    1091010924    if (!specifiers->isCustomPseudoElement()) {
     10925        if (tag == anyQName())
     10926            return;
    1091110927#if ENABLE(VIDEO_TRACK)
    1091210928        if (!(specifiers->pseudoType() == CSSSelector::PseudoCue))
    1091310929#endif
    10914             specifiers->setTag(tag);
     10930            specifiers->prependTagSelector(tag, tagIsForNamespaceRule);
    1091510931        return;
    1091610932    }
     
    1092510941
    1092610942    if (lastShadowDescendant->tagHistory()) {
    10927         lastShadowDescendant->tagHistory()->setTag(tag);
     10943        if (tag != anyQName())
     10944            lastShadowDescendant->tagHistory()->prependTagSelector(tag, tagIsForNamespaceRule);
    1092810945        return;
    1092910946    }
     
    1093110948    // For shadow-ID pseudo-elements to be correctly matched, the ShadowDescendant combinator has to be used.
    1093210949    // We therefore create a new Selector with that combinator here in any case, even if matching any (host) element in any namespace (i.e. '*').
    10933     OwnPtr<CSSParserSelector> elementNameSelector = adoptPtr(new CSSParserSelector);
    10934     elementNameSelector->setTag(tag);
     10950    OwnPtr<CSSParserSelector> elementNameSelector = adoptPtr(new CSSParserSelector(tag));
    1093510951    lastShadowDescendant->setTagHistory(elementNameSelector.release());
    1093610952    lastShadowDescendant->setRelation(CSSSelector::ShadowDescendant);
  • trunk/Source/WebCore/css/CSSParser.h

    r139866 r140371  
    267267
    268268    CSSParserSelector* createFloatingSelector();
     269    CSSParserSelector* createFloatingSelectorWithTagName(const QualifiedName&);
    269270    PassOwnPtr<CSSParserSelector> sinkFloatingSelector(CSSParserSelector*);
    270271
     
    317318    void addNamespace(const AtomicString& prefix, const AtomicString& uri);
    318319    QualifiedName determineNameInNamespace(const AtomicString& prefix, const AtomicString& localName);
    319     void updateSpecifiersWithElementName(const AtomicString& namespacePrefix, const AtomicString& elementName, CSSParserSelector*);
     320    void updateSpecifiersWithElementName(const AtomicString& namespacePrefix, const AtomicString& elementName, CSSParserSelector*, bool isNamespacePlaceholder = false);
     321    void updateSpecifiersWithNamespaceIfNeeded(CSSParserSelector*);
    320322    CSSParserSelector* updateSpecifiers(CSSParserSelector*, CSSParserSelector*);
    321323
  • trunk/Source/WebCore/css/CSSParserValues.cpp

    r134693 r140371  
    150150}
    151151
     152CSSParserSelector::CSSParserSelector(const QualifiedName& tagQName)
     153    : m_selector(adoptPtr(new CSSSelector(tagQName)))
     154{
     155}
     156
    152157CSSParserSelector::~CSSParserSelector()
    153158{
     
    172177}
    173178
     179bool CSSParserSelector::isSimple() const
     180{
     181    if (m_selector->selectorList() || m_selector->matchesPseudoElement())
     182        return false;
     183
     184    if (!m_tagHistory)
     185        return true;
     186
     187    if (m_selector->m_match == CSSSelector::Tag) {
     188        // We can't check against anyQName() here because namespace may not be nullAtom.
     189        // Example:
     190        //     @namespace "http://www.w3.org/2000/svg";
     191        //     svg:not(:root) { ...
     192        if (m_selector->tagQName().localName() == starAtom)
     193            return m_tagHistory->isSimple();
     194    }
     195
     196    return false;
     197}
     198
    174199void CSSParserSelector::insertTagHistory(CSSSelector::Relation before, PassOwnPtr<CSSParserSelector> selector, CSSSelector::Relation after)
    175200{
     
    190215}
    191216
    192 }
    193 
     217void CSSParserSelector::prependTagSelector(const QualifiedName& tagQName, bool tagIsForNamespaceRule)
     218{
     219    OwnPtr<CSSParserSelector> second = adoptPtr(new CSSParserSelector);
     220    second->m_selector = m_selector.release();
     221    second->m_tagHistory = m_tagHistory.release();
     222    m_tagHistory = second.release();
     223
     224    m_selector = adoptPtr(new CSSSelector(tagQName, tagIsForNamespaceRule));
     225    m_selector->m_relation = CSSSelector::SubSelector;
     226}
     227
     228}
     229
  • trunk/Source/WebCore/css/CSSParserValues.h

    r134693 r140371  
    173173public:
    174174    CSSParserSelector();
     175    explicit CSSParserSelector(const QualifiedName&);
    175176    ~CSSParserSelector();
    176177
    177178    PassOwnPtr<CSSSelector> releaseSelector() { return m_selector.release(); }
    178179
    179     void setTag(const QualifiedName& value) { m_selector->setTag(value); }
    180180    void setValue(const AtomicString& value) { m_selector->setValue(value); }
    181181    void setAttribute(const QualifiedName& value) { m_selector->setAttribute(value); }
     
    190190    bool isCustomPseudoElement() const { return m_selector->isCustomPseudoElement(); }
    191191
    192     bool isSimple() const { return !m_tagHistory && m_selector->isSimple(); }
     192    bool isSimple() const;
    193193    bool hasShadowDescendant() const;
    194194
     
    197197    void insertTagHistory(CSSSelector::Relation before, PassOwnPtr<CSSParserSelector>, CSSSelector::Relation after);
    198198    void appendTagHistory(CSSSelector::Relation, PassOwnPtr<CSSParserSelector>);
     199    void prependTagSelector(const QualifiedName&, bool tagIsForNamespaceRule = false);
    199200
    200201private:
  • trunk/Source/WebCore/css/CSSSelector.cpp

    r138784 r140371  
    4242void CSSSelector::createRareData()
    4343{
     44    ASSERT(m_match != Tag);
    4445    if (m_hasRareData)
    4546        return;
     
    5657    static const unsigned classMask = 0xff00;
    5758    static const unsigned elementMask = 0xff;
     59
     60    if (isForPage())
     61        return specificityForPage() & maxValueMask;
     62
    5863    unsigned total = 0;
    5964    unsigned temp = 0;
     65
    6066    for (const CSSSelector* selector = this; selector; selector = selector->tagHistory()) {
    61         if (selector->m_isForPage)
    62             return (total + selector->specificityForPage()) & maxValueMask;
    6367        temp = total + selector->specificityForOneSelector();
    6468        // Clamp each component to its max in the case of overflow.
     
    7983    // FIXME: Pseudo-elements and pseudo-classes do not have the same specificity. This function
    8084    // isn't quite correct.
    81     unsigned s = (m_tag.localName() == starAtom ? 0 : 1);
    8285    switch (m_match) {
    8386    case Id:
    84         s += 0x10000;
    85         break;
     87        return 0x10000;
    8688    case Exact:
    8789    case Class:
     
    9799        // See http://lists.w3.org/Archives/Public/www-style/2010Sep/0530.html
    98100        if (pseudoType() == PseudoNot && selectorList())
    99             s += selectorList()->first()->specificityForOneSelector();
    100         else
    101             s += 0x100;
    102     case None:
    103         break;
    104     }
    105     return s;
     101            return selectorList()->first()->specificityForOneSelector();
     102        return 0x100;
     103    case Tag:
     104        return (tagQName().localName() != starAtom) ? 1 : 0;
     105    case Unknown:
     106        return 0;
     107    }
     108    ASSERT_NOT_REACHED();
     109    return 0;
    106110}
    107111
     
    109113{
    110114    // See http://dev.w3.org/csswg/css3-page/#cascading-and-page-context
    111     unsigned s = (m_tag.localName() == starAtom ? 0 : 4);
    112 
    113     switch (pseudoType()) {
    114     case PseudoFirstPage:
    115         s += 2;
    116         break;
    117     case PseudoLeftPage:
    118     case PseudoRightPage:
    119         s += 1;
    120         break;
    121     case PseudoNotParsed:
    122         break;
    123     default:
    124         ASSERT_NOT_REACHED();
     115    unsigned s = 0;
     116
     117    for (const CSSSelector* component = this; component; component = component->tagHistory()) {
     118        switch (component->m_match) {
     119        case Tag:
     120            s += tagQName().localName() == starAtom ? 0 : 4;
     121            break;
     122        case PseudoClass:
     123            switch (component->pseudoType()) {
     124            case PseudoFirstPage:
     125                s += 2;
     126                break;
     127            case PseudoLeftPage:
     128            case PseudoRightPage:
     129                s += 1;
     130                break;
     131            case PseudoNotParsed:
     132                break;
     133            default:
     134                ASSERT_NOT_REACHED();
     135            }
     136            break;
     137        default:
     138            break;
     139        }
    125140    }
    126141    return s;
     
    552567
    553568    while (sel1 && sel2) {
    554         if (sel1->m_tag != sel2->m_tag || sel1->attribute() != sel2->attribute() ||
    555              sel1->relation() != sel2->relation() || sel1->m_match != sel2->m_match ||
    556              sel1->value() != sel2->value() ||
    557              sel1->pseudoType() != sel2->pseudoType() ||
    558              sel1->argument() != sel2->argument())
     569        if (sel1->attribute() != sel2->attribute()
     570            || sel1->relation() != sel2->relation()
     571            || sel1->m_match != sel2->m_match
     572            || sel1->value() != sel2->value()
     573            || sel1->pseudoType() != sel2->pseudoType()
     574            || sel1->argument() != sel2->argument()) {
    559575            return false;
     576        }
     577        if (sel1->m_match == Tag) {
     578            if (sel1->tagQName() != sel2->tagQName())
     579                return false;
     580        }
    560581        sel1 = sel1->tagHistory();
    561582        sel2 = sel2->tagHistory();
     
    572593    StringBuilder str;
    573594
    574     const AtomicString& prefix = m_tag.prefix();
    575     const AtomicString& localName = m_tag.localName();
    576     if (m_match == CSSSelector::None || !prefix.isNull() || localName != starAtom) {
    577         if (prefix.isNull())
    578             str.append(localName);
     595    if (m_match == CSSSelector::Tag && !m_tagIsForNamespaceRule) {
     596        if (tagQName().prefix().isNull())
     597            str.append(tagQName().localName());
    579598        else {
    580             str.append(prefix.string());
     599            str.append(tagQName().prefix().string());
    581600            str.append('|');
    582             str.append(localName);
     601            str.append(tagQName().localName());
    583602        }
    584603    }
     
    725744}
    726745
    727 bool CSSSelector::isSimple() const
    728 {
    729     if (selectorList() || tagHistory() || matchesPseudoElement())
    730         return false;
    731 
    732     int numConditions = 0;
    733 
    734     // hasTag() cannot be be used here because namespace may not be nullAtom.
    735     // Example:
    736     //     @namespace "http://www.w3.org/2000/svg";
    737     //     svg:not(:root) { ...
    738     if (m_tag != starAtom)
    739         numConditions++;
    740 
    741     if (m_match == Id || m_match == Class || m_match == PseudoClass)
    742         numConditions++;
    743 
    744     if (m_hasRareData && m_data.m_rareData->m_attribute != anyQName())
    745         numConditions++;
    746 
    747     // numConditions is 0 for a universal selector.
    748     // numConditions is 1 for other simple selectors.
    749     return numConditions <= 1;
    750 }
    751 
    752746CSSSelector::RareData::RareData(PassRefPtr<AtomicStringImpl> value)
    753747    : m_value(value.leakRef())
  • trunk/Source/WebCore/css/CSSSelector.h

    r139432 r140371  
    22 * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org)
    33 *               1999 Waldo Bastian (bastian@kde.org)
    4  * Copyright (C) 2004, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
     4 * Copyright (C) 2004, 2006, 2007, 2008, 2009, 2010, 2013 Apple Inc. All rights reserved.
    55 *
    66 * This library is free software; you can redistribute it and/or
     
    3838        CSSSelector();
    3939        CSSSelector(const CSSSelector&);
     40        explicit CSSSelector(const QualifiedName&, bool tagIsForNamespaceRule = false);
    4041
    4142        ~CSSSelector();
     
    5556        /* how the attribute value has to match.... Default is Exact */
    5657        enum Match {
    57             None = 0,
     58            Unknown = 0,
     59            Tag,
    5860            Id,
    5961            Class,
     
    199201        CSSSelector* tagHistory() const { return m_isLastInTagHistory ? 0 : const_cast<CSSSelector*>(this + 1); }
    200202
    201         bool hasTag() const { return m_tag != anyQName(); }
    202 
    203         const QualifiedName& tag() const { return m_tag; }
     203        const QualifiedName& tagQName() const;
    204204        // AtomicString is really just an AtomicStringImpl* so the cast below is safe.
    205205        // FIXME: Perhaps call sites could be changed to accept AtomicStringImpl?
     
    209209        CSSSelectorList* selectorList() const { return m_hasRareData ? m_data.m_rareData->m_selectorList.get() : 0; }
    210210
    211         void setTag(const QualifiedName& value) { m_tag = value; }
    212211        void setValue(const AtomicString&);
    213212        void setAttribute(const QualifiedName&);
     
    246245        bool m_hasRareData            : 1;
    247246        bool m_isForPage              : 1;
     247        bool m_tagIsForNamespaceRule  : 1;
    248248
    249249        unsigned specificityForOneSelector() const;
     
    276276            DataUnion() : m_value(0) { }
    277277            AtomicStringImpl* m_value;
     278            QualifiedName::QualifiedNameImpl* m_tagQName;
    278279            RareData* m_rareData;
    279280        } m_data;
    280 
    281         QualifiedName m_tag;
    282281    };
    283282
     
    337336inline void CSSSelector::setValue(const AtomicString& value)
    338337{
     338    ASSERT(m_match != Tag);
    339339    // Need to do ref counting manually for the union.
    340340    if (m_hasRareData) {
     
    361361inline CSSSelector::CSSSelector()
    362362    : m_relation(Descendant)
    363     , m_match(None)
     363    , m_match(Unknown)
    364364    , m_pseudoType(PseudoNotParsed)
    365365    , m_parsedNth(false)
     
    368368    , m_hasRareData(false)
    369369    , m_isForPage(false)
    370     , m_tag(anyQName())
    371 {
     370    , m_tagIsForNamespaceRule(false)
     371{
     372}
     373
     374inline CSSSelector::CSSSelector(const QualifiedName& tagQName, bool tagIsForNamespaceRule)
     375    : m_relation(Descendant)
     376    , m_match(Tag)
     377    , m_pseudoType(PseudoNotParsed)
     378    , m_parsedNth(false)
     379    , m_isLastInSelectorList(false)
     380    , m_isLastInTagHistory(true)
     381    , m_hasRareData(false)
     382    , m_isForPage(false)
     383    , m_tagIsForNamespaceRule(tagIsForNamespaceRule)
     384{
     385    m_data.m_tagQName = tagQName.impl();
     386    m_data.m_tagQName->ref();
    372387}
    373388
     
    381396    , m_hasRareData(o.m_hasRareData)
    382397    , m_isForPage(o.m_isForPage)
    383     , m_tag(o.m_tag)
    384 {
    385     if (o.m_hasRareData) {
     398    , m_tagIsForNamespaceRule(o.m_tagIsForNamespaceRule)
     399{
     400    if (o.m_match == Tag) {
     401        m_data.m_tagQName = o.m_data.m_tagQName;
     402        m_data.m_tagQName->ref();
     403    } else if (o.m_hasRareData) {
    386404        m_data.m_rareData = o.m_data.m_rareData;
    387405        m_data.m_rareData->ref();
     
    394412inline CSSSelector::~CSSSelector()
    395413{
    396     if (m_hasRareData)
     414    if (m_match == Tag)
     415        m_data.m_tagQName->deref();
     416    else if (m_hasRareData)
    397417        m_data.m_rareData->deref();
    398418    else if (m_data.m_value)
     
    400420}
    401421
     422inline const QualifiedName& CSSSelector::tagQName() const
     423{
     424    ASSERT(m_match == Tag);
     425    return *reinterpret_cast<const QualifiedName*>(&m_data.m_tagQName);
     426}
     427
    402428} // namespace WebCore
    403429
  • trunk/Source/WebCore/css/CSSSelectorList.cpp

    r134693 r140371  
    184184    bool operator()(CSSSelector* selector)
    185185    {
    186         if (selector->hasTag() && selector->tag().prefix() != nullAtom && selector->tag().prefix() != starAtom)
     186        if (selector->m_match == CSSSelector::Tag && selector->tagQName().prefix() != nullAtom && selector->tagQName().prefix() != starAtom)
    187187            return true;
    188188        if (selector->isAttributeSelector() && selector->attribute().prefix() != nullAtom && selector->attribute().prefix() != starAtom)
  • trunk/Source/WebCore/css/RuleSet.cpp

    r140173 r140371  
    5656static inline bool isSelectorMatchingHTMLBasedOnRuleHash(const CSSSelector* selector)
    5757{
    58     const AtomicString& selectorNamespace = selector->tag().namespaceURI();
    59     if (selectorNamespace != starAtom && selectorNamespace != xhtmlNamespaceURI)
    60         return false;
    61     if (selector->m_match == CSSSelector::None)
    62         return true;
    63     if (selector->tag() != starAtom)
    64         return false;
     58    ASSERT(selector);
     59    if (selector->m_match == CSSSelector::Tag) {
     60        const AtomicString& selectorNamespace = selector->tagQName().namespaceURI();
     61        if (selectorNamespace != starAtom && selectorNamespace != xhtmlNamespaceURI)
     62            return false;
     63        if (selector->relation() == CSSSelector::SubSelector)
     64            return isSelectorMatchingHTMLBasedOnRuleHash(selector->tagHistory());
     65        return true;
     66    }
    6567    if (SelectorChecker::isCommonPseudoClassSelector(selector))
    6668        return true;
     
    7375    if (!selectorList)
    7476        return false;
    75     for (CSSSelector* subSelector = selectorList->first(); subSelector; subSelector = CSSSelectorList::next(subSelector)) {
    76         if (subSelector->isAttributeSelector())
    77             return true;
     77    for (CSSSelector* selector = selectorList->first(); selector; selector = CSSSelectorList::next(selector)) {
     78        for (CSSSelector* component = selector; component; component = component->tagHistory()) {
     79            if (component->isAttributeSelector())
     80                return true;
     81        }
    7882    }
    7983    return false;
     
    114118        return PropertyWhitelistRegion;
    115119#if ENABLE(VIDEO_TRACK)
    116     if (selector->pseudoType() == CSSSelector::PseudoCue)
    117         return PropertyWhitelistCue;
     120    for (const CSSSelector* component = selector; component; component = component->tagHistory()) {
     121        if (component->pseudoType() == CSSSelector::PseudoCue)
     122            return PropertyWhitelistCue;
     123    }
    118124#endif
    119125    return PropertyWhitelistNone;
     
    207213}
    208214
    209 void RuleSet::addRule(StyleRule* rule, unsigned selectorIndex, AddRuleFlags addRuleFlags)
    210 {
    211     RuleData ruleData(rule, selectorIndex, m_ruleCount++, addRuleFlags);
    212 
    213     collectFeaturesFromRuleData(m_features, ruleData);
    214 
    215     CSSSelector* selector = ruleData.selector();
    216 
    217     if (selector->m_match == CSSSelector::Id) {
    218         addToRuleSet(selector->value().impl(), m_idRules, ruleData);
    219         return;
    220     }
    221     if (selector->m_match == CSSSelector::Class) {
    222         addToRuleSet(selector->value().impl(), m_classRules, ruleData);
    223         return;
    224     }
    225     if (selector->isCustomPseudoElement()) {
    226         addToRuleSet(selector->value().impl(), m_shadowPseudoElementRules, ruleData);
    227         return;
     215bool RuleSet::findBestRuleSetAndAdd(const CSSSelector* component, RuleData& ruleData)
     216{
     217    if (component->m_match == CSSSelector::Id) {
     218        addToRuleSet(component->value().impl(), m_idRules, ruleData);
     219        return true;
     220    }
     221    if (component->m_match == CSSSelector::Class) {
     222        addToRuleSet(component->value().impl(), m_classRules, ruleData);
     223        return true;
     224    }
     225    if (component->isCustomPseudoElement()) {
     226        addToRuleSet(component->value().impl(), m_shadowPseudoElementRules, ruleData);
     227        return true;
    228228    }
    229229#if ENABLE(VIDEO_TRACK)
    230     if (selector->pseudoType() == CSSSelector::PseudoCue) {
     230    if (component->pseudoType() == CSSSelector::PseudoCue) {
    231231        m_cuePseudoRules.append(ruleData);
    232         return;
    233     }
    234 #endif
    235     if (SelectorChecker::isCommonPseudoClassSelector(selector)) {
    236         switch (selector->pseudoType()) {
     232        return true;
     233    }
     234#endif
     235    if (SelectorChecker::isCommonPseudoClassSelector(component)) {
     236        switch (component->pseudoType()) {
    237237        case CSSSelector::PseudoLink:
    238238        case CSSSelector::PseudoVisited:
    239239        case CSSSelector::PseudoAnyLink:
    240240            m_linkPseudoClassRules.append(ruleData);
    241             return;
     241            return true;
    242242        case CSSSelector::PseudoFocus:
    243243            m_focusPseudoClassRules.append(ruleData);
    244             return;
     244            return true;
    245245        default:
    246246            ASSERT_NOT_REACHED();
    247         }
    248         return;
    249     }
    250     const AtomicString& localName = selector->tag().localName();
    251     if (localName != starAtom) {
    252         addToRuleSet(localName.impl(), m_tagRules, ruleData);
    253         return;
    254     }
    255     m_universalRules.append(ruleData);
     247            return true;
     248        }
     249    }
     250
     251    if (component->m_match == CSSSelector::Tag) {
     252        if (component->tagQName().localName() != starAtom) {
     253            // If this is part of a subselector chain, recurse ahead to find a narrower set (ID/class.)
     254            if (component->relation() == CSSSelector::SubSelector
     255                && (component->tagHistory()->m_match == CSSSelector::Class || component->tagHistory()->m_match == CSSSelector::Id || SelectorChecker::isCommonPseudoClassSelector(component->tagHistory()))
     256                && findBestRuleSetAndAdd(component->tagHistory(), ruleData))
     257                return true;
     258
     259            addToRuleSet(component->tagQName().localName().impl(), m_tagRules, ruleData);
     260            return true;
     261        }
     262    }
     263    return false;
     264}
     265
     266void RuleSet::addRule(StyleRule* rule, unsigned selectorIndex, AddRuleFlags addRuleFlags)
     267{
     268    RuleData ruleData(rule, selectorIndex, m_ruleCount++, addRuleFlags);
     269    collectFeaturesFromRuleData(m_features, ruleData);
     270
     271    if (!findBestRuleSetAndAdd(ruleData.selector(), ruleData)) {
     272        // If we didn't find a specialized map to stick it in, file under universal rules.
     273        m_universalRules.append(ruleData);
     274    }
    256275}
    257276
  • trunk/Source/WebCore/css/RuleSet.h

    r140173 r140371  
    139139private:
    140140    void addChildRules(const Vector<RefPtr<StyleRuleBase> >&, const MediaQueryEvaluator& medium, StyleResolver*, const ContainerNode* scope, bool hasDocumentSecurityOrigin, AddRuleFlags);
     141    bool findBestRuleSetAndAdd(const CSSSelector*, RuleData&);
    141142
    142143public:
  • trunk/Source/WebCore/css/SelectorChecker.cpp

    r140235 r140371  
    33 *           (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com)
    44 * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com)
    5  * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
     5 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All rights reserved.
    66 * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
    77 * Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org>
     
    8080
    8181    PseudoId ignoreDynamicPseudo = NOPSEUDO;
    82     return match(SelectorCheckingContext(sel, element, SelectorChecker::VisitedMatchDisabled), ignoreDynamicPseudo) == SelectorMatches;
     82    return match(SelectorCheckingContext(sel, element, SelectorChecker::VisitedMatchDisabled), ignoreDynamicPseudo, DOMSiblingTraversalStrategy()) == SelectorMatches;
    8383}
    8484
    8585namespace {
    8686
    87 template <bool checkValue(const Element*, AtomicStringImpl*, const QualifiedName&), bool initAttributeName>
     87template <bool checkValue(const Element*, const CSSSelector*)>
    8888inline bool fastCheckSingleSelector(const CSSSelector*& selector, const Element*& element, const CSSSelector*& topChildOrSubselector, const Element*& topChildOrSubselectorMatchElement)
    8989{
    90     AtomicStringImpl* value = selector->value().impl();
    91     const QualifiedName& attribute = initAttributeName ? selector->attribute() : anyQName();
    9290    for (; element; element = element->parentElement()) {
    93         if (checkValue(element, value, attribute) && SelectorChecker::tagMatches(element, selector)) {
     91        if (checkValue(element, selector)) {
    9492            if (selector->relation() == CSSSelector::Descendant)
    9593                topChildOrSubselector = 0;
     
    121119}
    122120
    123 inline bool checkClassValue(const Element* element, AtomicStringImpl* value, const QualifiedName&)
    124 {
    125     return element->hasClass() && static_cast<const StyledElement*>(element)->classNames().contains(value);
    126 }
    127 
    128 inline bool checkIDValue(const Element* element, AtomicStringImpl* value, const QualifiedName&)
    129 {
    130     return element->hasID() && element->idForStyleResolution().impl() == value;
    131 }
    132 
    133 inline bool checkExactAttributeValue(const Element* element, AtomicStringImpl* value, const QualifiedName& attributeName)
    134 {
    135     return SelectorChecker::checkExactAttribute(element, attributeName, value);
    136 }
    137 
    138 inline bool checkTagValue(const Element*, AtomicStringImpl*, const QualifiedName&)
    139 {
    140     return true;
     121inline bool checkClassValue(const Element* element, const CSSSelector* selector)
     122{
     123    return element->hasClass() && static_cast<const StyledElement*>(element)->classNames().contains(selector->value().impl());
     124}
     125
     126inline bool checkIDValue(const Element* element, const CSSSelector* selector)
     127{
     128    return element->hasID() && element->idForStyleResolution().impl() == selector->value().impl();
     129}
     130
     131inline bool checkExactAttributeValue(const Element* element, const CSSSelector* selector)
     132{
     133    return SelectorChecker::checkExactAttribute(element, selector->attribute(), selector->value().impl());
     134}
     135
     136inline bool checkTagValue(const Element* element, const CSSSelector* selector)
     137{
     138    return SelectorChecker::tagMatches(element, selector->tagQName());
    141139}
    142140
     
    147145    ASSERT(isFastCheckableSelector(selector));
    148146
    149     if (!SelectorChecker::tagMatches(element, selector))
    150         return false;
    151147    switch (selector->m_match) {
    152     case CSSSelector::None:
    153         return true;
     148    case CSSSelector::Tag:
     149        return checkTagValue(element, selector);
    154150    case CSSSelector::Class:
    155         return checkClassValue(element, selector->value().impl(), anyQName());
     151        return checkClassValue(element, selector);
    156152    case CSSSelector::Id:
    157         return checkIDValue(element, selector->value().impl(), anyQName());
     153        return checkIDValue(element, selector);
    158154    case CSSSelector::Exact:
    159155    case CSSSelector::Set:
    160         return checkExactAttributeValue(element, selector->value().impl(), selector->attribute());
     156        return checkExactAttributeValue(element, selector);
    161157    case CSSSelector::PseudoClass:
    162158        return commonPseudoClassSelectorMatches(element, selector, visitedMatchType);
     
    185181        switch (selector->m_match) {
    186182        case CSSSelector::Class:
    187             if (!fastCheckSingleSelector<checkClassValue, false>(selector, element, topChildOrSubselector, topChildOrSubselectorMatchElement))
     183            if (!fastCheckSingleSelector<checkClassValue>(selector, element, topChildOrSubselector, topChildOrSubselectorMatchElement))
    188184                return false;
    189185            break;
    190186        case CSSSelector::Id:
    191             if (!fastCheckSingleSelector<checkIDValue, false>(selector, element, topChildOrSubselector, topChildOrSubselectorMatchElement))
    192                 return false;
    193             break;
    194         case CSSSelector::None:
    195             if (!fastCheckSingleSelector<checkTagValue, false>(selector, element, topChildOrSubselector, topChildOrSubselectorMatchElement))
     187            if (!fastCheckSingleSelector<checkIDValue>(selector, element, topChildOrSubselector, topChildOrSubselectorMatchElement))
     188                return false;
     189            break;
     190        case CSSSelector::Tag:
     191            if (!fastCheckSingleSelector<checkTagValue>(selector, element, topChildOrSubselector, topChildOrSubselectorMatchElement))
    196192                return false;
    197193            break;
    198194        case CSSSelector::Set:
    199195        case CSSSelector::Exact:
    200             if (!fastCheckSingleSelector<checkExactAttributeValue, true>(selector, element, topChildOrSubselector, topChildOrSubselectorMatchElement))
     196            if (!fastCheckSingleSelector<checkExactAttributeValue>(selector, element, topChildOrSubselector, topChildOrSubselectorMatchElement))
    201197                return false;
    202198            break;
     
    222218    if (selector->m_match == CSSSelector::Exact)
    223219        return selector->attribute() != styleAttr && !htmlAttributeHasCaseInsensitiveValue(selector->attribute());
    224     return selector->m_match == CSSSelector::None || selector->m_match == CSSSelector::Id || selector->m_match == CSSSelector::Class;
     220    return selector->m_match == CSSSelector::Tag || selector->m_match == CSSSelector::Id || selector->m_match == CSSSelector::Class;
    225221}
    226222
     
    251247// * SelectorFailsAllSiblings - the selector fails for e and any sibling of e
    252248// * SelectorFailsCompletely  - the selector fails for e and any sibling or ancestor of e
    253 SelectorChecker::Match SelectorChecker::match(const SelectorCheckingContext& context, PseudoId& dynamicPseudo) const
     249template<typename SiblingTraversalStrategy>
     250SelectorChecker::Match SelectorChecker::match(const SelectorCheckingContext& context, PseudoId& dynamicPseudo, const SiblingTraversalStrategy& siblingTraversalStrategy) const
    254251{
    255252    // first selector has to match
    256     if (!checkOne(context, DOMSiblingTraversalStrategy()))
     253    if (!checkOne(context, siblingTraversalStrategy))
    257254        return SelectorFailsLocally;
    258255
     
    316313        nextContext.elementParentStyle = 0;
    317314        for (; nextContext.element; nextContext.element = nextContext.element->parentElement()) {
    318             Match match = this->match(nextContext, ignoreDynamicPseudo);
     315            Match match = this->match(nextContext, ignoreDynamicPseudo, siblingTraversalStrategy);
    319316            if (match == SelectorMatches || match == SelectorFailsCompletely)
    320317                return match;
     
    331328        nextContext.elementStyle = 0;
    332329        nextContext.elementParentStyle = 0;
    333         return match(nextContext, ignoreDynamicPseudo);
     330        return match(nextContext, ignoreDynamicPseudo, siblingTraversalStrategy);
    334331
    335332    case CSSSelector::DirectAdjacent:
     
    344341        nextContext.elementStyle = 0;
    345342        nextContext.elementParentStyle = 0;
    346         return match(nextContext, ignoreDynamicPseudo);
     343        return match(nextContext, ignoreDynamicPseudo, siblingTraversalStrategy);
    347344
    348345    case CSSSelector::IndirectAdjacent:
     
    356353        nextContext.elementParentStyle = 0;
    357354        for (; nextContext.element; nextContext.element = nextContext.element->previousElementSibling()) {
    358             Match match = this->match(nextContext, ignoreDynamicPseudo);
     355            Match match = this->match(nextContext, ignoreDynamicPseudo, siblingTraversalStrategy);
    359356            if (match == SelectorMatches || match == SelectorFailsAllSiblings || match == SelectorFailsCompletely)
    360357                return match;
     
    373370            return SelectorFailsCompletely;
    374371        nextContext.isSubSelector = true;
    375         return match(nextContext, dynamicPseudo);
     372        return match(nextContext, dynamicPseudo, siblingTraversalStrategy);
    376373
    377374    case CSSSelector::ShadowDescendant:
     
    387384            nextContext.elementStyle = 0;
    388385            nextContext.elementParentStyle = 0;
    389             return match(nextContext, ignoreDynamicPseudo);
     386            return match(nextContext, ignoreDynamicPseudo, siblingTraversalStrategy);
    390387        }
    391388    }
     
    549546    ASSERT(selector);
    550547
    551     if (!SelectorChecker::tagMatches(element, selector))
    552         return false;
     548    if (selector->m_match == CSSSelector::Tag)
     549        return SelectorChecker::tagMatches(element, selector->tagQName());
    553550
    554551    if (selector->m_match == CSSSelector::Class)
     
    770767                PseudoId ignoreDynamicPseudo = NOPSEUDO;
    771768                for (subContext.selector = selector->selectorList()->first(); subContext.selector; subContext.selector = CSSSelectorList::next(subContext.selector)) {
    772                     if (match(subContext, ignoreDynamicPseudo) == SelectorMatches)
     769                    if (match(subContext, ignoreDynamicPseudo, siblingTraversalStrategy) == SelectorMatches)
    773770                        return true;
    774771                }
     
    803800            // If we're in quirks mode, then hover should never match anchors with no
    804801            // href and *:hover should not match anything. This is important for sites like wsj.com.
    805             if (m_strictParsing || context.isSubSelector || (selector->hasTag() && !element->hasTagName(aTag)) || element->isLink()) {
     802            if (m_strictParsing || context.isSubSelector || (selector->m_match == CSSSelector::Tag && selector->tagQName() != anyQName() && !element->hasTagName(aTag)) || element->isLink()) {
    806803                if (m_mode == ResolvingStyle) {
    807804                    if (context.elementStyle)
     
    817814            // If we're in quirks mode, then :active should never match anchors with no
    818815            // href and *:active should not match anything.
    819             if (m_strictParsing || context.isSubSelector || (selector->hasTag() && !element->hasTagName(aTag)) || element->isLink()) {
     816            if (m_strictParsing || context.isSubSelector || (selector->m_match == CSSSelector::Tag && selector->tagQName() != anyQName() && !element->hasTagName(aTag)) || element->isLink()) {
    820817                if (m_mode == ResolvingStyle) {
    821818                    if (context.elementStyle)
     
    977974        CSSSelector* const & selector = context.selector;
    978975        for (subContext.selector = selector->selectorList()->first(); subContext.selector; subContext.selector = CSSSelectorList::next(subContext.selector)) {
    979             if (match(subContext, ignoreDynamicPseudo) == SelectorMatches)
     976            if (match(subContext, ignoreDynamicPseudo, siblingTraversalStrategy) == SelectorMatches)
    980977                return true;
    981978        }
     
    11361133
    11371134template
    1138 bool SelectorChecker::checkOne(const SelectorChecker::SelectorCheckingContext&, const ShadowDOMSiblingTraversalStrategy&) const;
    1139 
    1140 }
     1135SelectorChecker::Match SelectorChecker::match(const SelectorCheckingContext&, PseudoId&, const DOMSiblingTraversalStrategy&) const;
     1136
     1137template
     1138SelectorChecker::Match SelectorChecker::match(const SelectorCheckingContext&, PseudoId&, const ShadowDOMSiblingTraversalStrategy&) const;
     1139
     1140}
  • trunk/Source/WebCore/css/SelectorChecker.h

    r140235 r140371  
    33 *           (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com)
    44 * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com)
    5  * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
     5 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All rights reserved.
    66 * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
    77 * Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org>
     
    7979
    8080    bool matches(CSSSelector*, Element*, bool isFastCheckableSelector = false) const;
    81     Match match(const SelectorCheckingContext&, PseudoId&) const;
     81    template<typename SiblingTraversalStrategy>
     82    Match match(const SelectorCheckingContext&, PseudoId&, const SiblingTraversalStrategy&) const;
    8283    template<typename SiblingTraversalStrategy>
    8384    bool checkOne(const SelectorCheckingContext&, const SiblingTraversalStrategy&) const;
     
    9192    void setMode(Mode mode) { m_mode = mode; }
    9293
    93     static bool tagMatches(const Element*, const CSSSelector*);
     94    static bool tagMatches(const Element*, const QualifiedName&);
    9495    static bool isCommonPseudoClassSelector(const CSSSelector*);
    9596    bool matchesFocusPseudoClass(const Element*) const;
     
    130131}
    131132
    132 inline bool SelectorChecker::tagMatches(const Element* element, const CSSSelector* selector)
     133inline bool SelectorChecker::tagMatches(const Element* element, const QualifiedName& tagQName)
    133134{
    134     if (!selector->hasTag())
     135    if (tagQName == anyQName())
    135136        return true;
    136     const AtomicString& localName = selector->tag().localName();
     137    const AtomicString& localName = tagQName.localName();
    137138    if (localName != starAtom && localName != element->localName())
    138139        return false;
    139     const AtomicString& namespaceURI = selector->tag().namespaceURI();
     140    const AtomicString& namespaceURI = tagQName.namespaceURI();
    140141    return namespaceURI == starAtom || namespaceURI == element->namespaceURI();
    141142}
  • trunk/Source/WebCore/css/SelectorFilter.cpp

    r138432 r140371  
    110110}
    111111
    112 static inline void collectDescendantSelectorIdentifierHashes(const CSSSelector* selector, unsigned*& hash, const unsigned* end)
     112static inline void collectDescendantSelectorIdentifierHashes(const CSSSelector* selector, unsigned*& hash)
    113113{
    114114    switch (selector->m_match) {
     
    121121            (*hash++) = selector->value().impl()->existingHash() * ClassAttributeSalt;
    122122        break;
     123    case CSSSelector::Tag:
     124        if (selector->tagQName().localName() != starAtom)
     125            (*hash++) = selector->tagQName().localName().impl()->existingHash() * TagNameSalt;
     126        break;
    123127    default:
    124128        break;
    125129    }
    126     if (hash == end)
    127         return;
    128     const AtomicString& localName = selector->tag().localName();
    129     if (localName != starAtom)
    130         (*hash++) = localName.impl()->existingHash() * TagNameSalt;
    131130}
    132131
     
    144143        case CSSSelector::SubSelector:
    145144            if (!skipOverSubselectors)
    146                 collectDescendantSelectorIdentifierHashes(selector, hash, end);
     145                collectDescendantSelectorIdentifierHashes(selector, hash);
    147146            break;
    148147        case CSSSelector::DirectAdjacent:
     
    154153        case CSSSelector::Child:
    155154            skipOverSubselectors = false;
    156             collectDescendantSelectorIdentifierHashes(selector, hash, end);
     155            collectDescendantSelectorIdentifierHashes(selector, hash);
    157156            break;
    158157        }
  • trunk/Source/WebCore/css/StyleResolver.cpp

    r140331 r140371  
    33 *           (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com)
    44 * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com)
    5  * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved.
     5 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All rights reserved.
    66 * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
    77 * Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org>
     
    22732273            if (!ruleData.hasMultipartSelector())
    22742274                return true;
    2275         } else if (!SelectorChecker::tagMatches(m_element, ruleData.selector()))
     2275        }
     2276        if (ruleData.selector()->m_match == CSSSelector::Tag && !SelectorChecker::tagMatches(m_element, ruleData.selector()->tagQName()))
    22762277            return false;
    22772278        if (!SelectorChecker::fastCheckRightmostAttributeSelector(m_element, ruleData.selector()))
     
    22862287    context.scope = scope;
    22872288    context.pseudoStyle = m_pseudoStyle;
    2288     SelectorChecker::Match match = m_selectorChecker.match(context, m_dynamicPseudo);
     2289    SelectorChecker::Match match = m_selectorChecker.match(context, m_dynamicPseudo, DOMSiblingTraversalStrategy());
    22892290    if (match != SelectorChecker::SelectorMatches)
    22902291        return false;
     
    26022603}
    26032604
    2604 void StyleResolver::matchPageRulesForList(Vector<StyleRulePage*>& matchedRules, const Vector<StyleRulePage*>& rules, bool isLeftPage, bool isFirstPage, const String& pageName)
    2605 {
    2606     unsigned size = rules.size();
    2607     for (unsigned i = 0; i < size; ++i) {
    2608         StyleRulePage* rule = rules[i];
    2609         const AtomicString& selectorLocalName = rule->selector()->tag().localName();
    2610         if (selectorLocalName != starAtom && selectorLocalName != pageName)
    2611             continue;
    2612         CSSSelector::PseudoType pseudoType = rule->selector()->pseudoType();
     2605static bool checkPageSelectorComponents(const CSSSelector* selector, bool isLeftPage, bool isFirstPage, const String& pageName)
     2606{
     2607    for (const CSSSelector* component = selector; component; component = component->tagHistory()) {
     2608        if (component->m_match == CSSSelector::Tag) {
     2609            const AtomicString& localName = component->tagQName().localName();
     2610            if (localName != starAtom && localName != pageName)
     2611                return false;
     2612        }
     2613
     2614        CSSSelector::PseudoType pseudoType = component->pseudoType();
    26132615        if ((pseudoType == CSSSelector::PseudoLeftPage && !isLeftPage)
    26142616            || (pseudoType == CSSSelector::PseudoRightPage && isLeftPage)
    26152617            || (pseudoType == CSSSelector::PseudoFirstPage && !isFirstPage))
     2618        {
     2619            return false;
     2620        }
     2621    }
     2622    return true;
     2623}
     2624
     2625void StyleResolver::matchPageRulesForList(Vector<StyleRulePage*>& matchedRules, const Vector<StyleRulePage*>& rules, bool isLeftPage, bool isFirstPage, const String& pageName)
     2626{
     2627    for (unsigned i = 0; i < rules.size(); ++i) {
     2628        StyleRulePage* rule = rules[i];
     2629
     2630        if (!checkPageSelectorComponents(rule->selector(), isLeftPage, isFirstPage, pageName))
    26162631            continue;
    26172632
  • trunk/Source/WebCore/dom/QualifiedName.cpp

    r131993 r140371  
    103103#endif
    104104    ASSERT(!isHashTableDeletedValue());
     105    m_impl->deref();
     106}
    105107
    106     if (m_impl->hasOneRef())
    107         gNameCache->remove(m_impl);
    108     m_impl->deref();
     108QualifiedName::QualifiedNameImpl::~QualifiedNameImpl()
     109{
     110    gNameCache->remove(this);
    109111}
    110112
  • trunk/Source/WebCore/dom/QualifiedName.h

    r131993 r140371  
    4444            return adoptRef(new QualifiedNameImpl(prefix, localName, namespaceURI));
    4545        }
     46
     47        ~QualifiedNameImpl();
    4648
    4749        unsigned computeHash() const;
  • trunk/Source/WebCore/html/shadow/ContentDistributor.cpp

    r140299 r140371  
    407407    if (ScopeContentDistribution::hasContentElement(root)) {
    408408        for (Element* element = ElementTraversal::firstWithin(root); element; element = ElementTraversal::next(element)) {
    409             if (isHTMLContentElement(element)) {
    410                 const CSSSelectorList& list = toHTMLContentElement(element)->selectorList();
    411                 for (CSSSelector* selector = list.first(); selector; selector = list.next(selector))
    412                     m_selectFeatures.collectFeaturesFromSelector(selector);
     409            if (!isHTMLContentElement(element))
     410                continue;
     411            const CSSSelectorList& list = toHTMLContentElement(element)->selectorList();
     412            for (CSSSelector* selector = list.first(); selector; selector = CSSSelectorList::next(selector)) {
     413                for (CSSSelector* component = selector; component; component = component->tagHistory())
     414                    m_selectFeatures.collectFeaturesFromSelector(component);
    413415            }
    414416        }
  • trunk/Source/WebCore/html/shadow/ContentSelectorQuery.cpp

    r139406 r140371  
    4646    SelectorChecker::SelectorCheckingContext context(selector, toElement(siblings[nth].get()), SelectorChecker::VisitedMatchEnabled);
    4747    ShadowDOMSiblingTraversalStrategy strategy(siblings, nth);
    48     return m_selectorChecker.checkOne(context, strategy);
     48    PseudoId ignoreDynamicPseudo = NOPSEUDO;
     49    return m_selectorChecker.match(context, ignoreDynamicPseudo, strategy) == SelectorChecker::SelectorMatches;
    4950}
    5051
  • trunk/Source/WebCore/html/shadow/HTMLContentElement.cpp

    r139410 r140371  
    121121{
    122122    switch (selector->m_match) {
    123     case CSSSelector::None:
     123    case CSSSelector::Tag:
    124124    case CSSSelector::Id:
    125125    case CSSSelector::Class:
Note: See TracChangeset for help on using the changeset viewer.