Changeset 85077 in webkit


Ignore:
Timestamp:
Apr 27, 2011 1:32:16 PM (13 years ago)
Author:
Dimitri Glazkov
Message:

2011-04-16 Dimitri Glazkov <Dimitri Glazkov>

Reviewed by Antti Koivisto.

Teach sub-selector chains about shadow descendants
https://bugs.webkit.org/show_bug.cgi?id=58342

  • fast/css/unknown-pseudo-element-matching-expected.txt: Updated expectations.
  • fast/css/unknown-pseudo-element-matching.html: Added new tests.

2011-04-20 Dimitri Glazkov <Dimitri Glazkov>

Reviewed by Antti Koivisto.

Teach sub-selector chains about shadow descendants
https://bugs.webkit.org/show_bug.cgi?id=58342

The primary change is to the logic of parsing specifiers:
1) The shadow descendant selectors (those specifiers that are unknown
pseudo element selectors) are always kept at the top of the chain.
2) The sub-selectors after shadow descendant selectors are stashed right
behind the sub-selector, but not at the end of the chain.
3) Other sub-selectors are appended at the end of the chain.

  • css/CSSGrammar.y: Changed specifier_list collection to use new

CSSParser::updateSpecifier helper.

  • css/CSSParser.cpp: (WebCore::CSSParser::updateSpecifiersWithElementName): Added logic to

look for the last ShadowDescendant relation in the chain of selectors,
because the next selector after it is the one that should get the
element name.

(WebCore::CSSParser::updateSpecifiers): Moved and modified the logic from

CSSGrammar.y. The new logic adjusts the selector chain to allow
shadow descendant selectors have sub-selectors (and have multiple shadow
descendants in the chain).

  • css/CSSParser.h: Added decl.
  • css/CSSParserValues.cpp: (WebCore::CSSParserSelector::insertTagHistory): Added. (WebCore::CSSParserSelector::appendTagHistory): Aded.
  • css/CSSParserValues.h: Added decls.
  • css/CSSStyleSelector.cpp: (WebCore::CSSStyleSelector::SelectorChecker::checkOneSelector): Added

shadow descendant selector match check, since now there could be many
of them in the selector chain.

Location:
trunk
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r85075 r85077  
     12011-04-16  Dimitri Glazkov  <dglazkov@chromium.org>
     2
     3        Reviewed by Antti Koivisto.
     4
     5        Teach sub-selector chains about shadow descendants
     6        https://bugs.webkit.org/show_bug.cgi?id=58342
     7
     8        * fast/css/unknown-pseudo-element-matching-expected.txt: Updated expectations.
     9        * fast/css/unknown-pseudo-element-matching.html: Added new tests.
     10
    1112011-04-20  Adrienne Walker  <enne@google.com>
    212
  • trunk/LayoutTests/fast/css/unknown-pseudo-element-matching-expected.txt

    r75543 r85077  
    11Tests various selector combinations, containing unknown pseudo element selectors.
    22
     3Basic selector tests:
    34::-webkit-slider-thumb should match: PASS
    45::-webkit-slider-thumb, where HTML is not default namespace should not match: PASS
     
    2526input#foo[type=range]::-webkit-slider-thumb should match: PASS
    2627input.bar[type=range]::-webkit-slider-thumb should match: PASS
     28
     29Shouldn't ignore selector after the unknown pseudo element:
     30::-webkit-slider-thumb:disabled should not match: PASS
     31input::-webkit-slider-thumb:disabled should not match: PASS
     32#foo::-webkit-slider-thumb:disabled should not match: PASS
     33input#foo::-webkit-slider-thumb:disabled should not match: PASS
     34input.bar::-webkit-slider-thumb:disabled should not match: PASS
     35input[type=range]::-webkit-slider-thumb:disabled should not match: PASS
     36
     37Should not match disabled input, because the disabled state is on the input, not the thumb:
     38::-webkit-slider-thumb:disabled should not match: PASS
     39input::-webkit-slider-thumb:disabled should not match: PASS
     40#foo::-webkit-slider-thumb:disabled should not match: PASS
     41input#foo::-webkit-slider-thumb:disabled should not match: PASS
     42input.bar::-webkit-slider-thumb:disabled should not match: PASS
     43input[type=range]::-webkit-slider-thumb:disabled should not match: PASS
     44
     45Should match :hover when the mouse is over the slider thumb:
     46::-webkit-slider-thumb:hover should match: PASS
     47input::-webkit-slider-thumb:hover should match: PASS
     48#foo::-webkit-slider-thumb:hover should match: PASS
     49input#foo::-webkit-slider-thumb:hover should match: PASS
     50input.bar::-webkit-slider-thumb:hover should match: PASS
     51input[type=range]::-webkit-slider-thumb:hover should match: PASS
  • trunk/LayoutTests/fast/css/unknown-pseudo-element-matching.html

    r75543 r85077  
    1717var NAMESPACE_DECLARATION = '@namespace "http://example.com/foo/namespace";\n@namespace html "http://www.w3.org/1999/xhtml";\n';
    1818var SELECTOR_TEST_PROPERTIES = ' { height: 1px; -webkit-appearance: none; }';
     19var SELECTORS = [
     20'::-webkit-slider-thumb',
     21'input::-webkit-slider-thumb',
     22'#foo::-webkit-slider-thumb',
     23'input#foo::-webkit-slider-thumb',
     24'input.bar::-webkit-slider-thumb',
     25'input[type=range]::-webkit-slider-thumb'
     26];
     27var DISABLED_SELECTORS = SELECTORS.map(function(selector) { return selector + ':disabled'; });
     28var HOVER_SELECTORS = SELECTORS.map(function(selector) { return selector + ':hover'; })
    1929
    2030// convenience constants
     
    2535function log(msg, success)
    2636{
    27     logDiv.appendChild(document.createElement('div')).innerHTML = msg + ': ' + (success ? 'PASS' : 'FAIL');
     37    logDiv.appendChild(document.createElement('div')).innerHTML = msg + (arguments.length == 1 ? '' : (': ' + (success ? 'PASS' : 'FAIL')));
     38}
     39
     40function hoverOverSliderThumb()
     41{
     42    if (!window.eventSender)
     43        return false;
     44
     45    var x = input.offsetLeft + input.offsetWidth / 2;
     46    var y = input.offsetTop + input.offsetHeight / 2;
     47    eventSender.mouseMoveTo(x, y);
     48    return true;
    2849}
    2950
     
    4364    input = document.getElementsByTagName('input')[0];
    4465    logDiv = document.getElementById('log');
     66    log('Basic selector tests:');
    4567    runSelectorTest(MATCH, '::-webkit-slider-thumb');
    4668    runSelectorTest(NO_MATCH, '::-webkit-slider-thumb', WITH_NAMESPACES);
     
    6789    runSelectorTest(MATCH, 'input#foo[type=range]::-webkit-slider-thumb');
    6890    runSelectorTest(MATCH, 'input.bar[type=range]::-webkit-slider-thumb');
     91    log('<br>Shouldn\'t ignore selector after the unknown pseudo element:');
     92    DISABLED_SELECTORS.forEach(expectNoMatch);
     93    input.disabled = true;
     94    log('<br>Should not match disabled input, because the disabled state is on the input, not the thumb:');
     95    DISABLED_SELECTORS.forEach(expectNoMatch);
     96    input.disabled = false;
     97    if (!hoverOverSliderThumb()) {
     98        log(':hover tests require DRT');
     99        return;
     100    }
     101    log('<br>Should match :hover when the mouse is over the slider thumb:');
     102    HOVER_SELECTORS.forEach(expectMatch);
    69103    document.body.removeChild(input);
     104}
     105
     106function expectNoMatch(selector) {
     107    runSelectorTest(NO_MATCH, selector);
     108}
     109
     110function expectMatch(selector) {
     111    runSelectorTest(MATCH, selector);
    70112}
    71113
  • trunk/Source/WebCore/ChangeLog

    r85075 r85077  
     12011-04-20  Dimitri Glazkov  <dglazkov@chromium.org>
     2
     3        Reviewed by Antti Koivisto.
     4
     5        Teach sub-selector chains about shadow descendants
     6        https://bugs.webkit.org/show_bug.cgi?id=58342
     7
     8        The primary change is to the logic of parsing specifiers:
     9        1) The shadow descendant selectors (those specifiers that are unknown
     10        pseudo element selectors) are always kept at the top of the chain.
     11        2) The sub-selectors after shadow descendant selectors are stashed right
     12        behind the sub-selector, but not at the end of the chain.
     13        3) Other sub-selectors are appended at the end of the chain.
     14
     15        * css/CSSGrammar.y: Changed specifier_list collection to use new
     16            CSSParser::updateSpecifier helper.
     17        * css/CSSParser.cpp:
     18        (WebCore::CSSParser::updateSpecifiersWithElementName): Added logic to
     19            look for the last ShadowDescendant relation in the chain of selectors,
     20            because the next selector after it is the one that should get the
     21            element name.
     22        (WebCore::CSSParser::updateSpecifiers): Moved and modified the logic from
     23            CSSGrammar.y. The new logic adjusts the selector chain to allow
     24            shadow descendant selectors have sub-selectors (and have multiple shadow
     25            descendants in the chain).
     26        * css/CSSParser.h: Added decl.
     27        * css/CSSParserValues.cpp:
     28        (WebCore::CSSParserSelector::insertTagHistory): Added.
     29        (WebCore::CSSParserSelector::appendTagHistory): Aded.
     30        * css/CSSParserValues.h: Added decls.
     31        * css/CSSStyleSelector.cpp:
     32        (WebCore::CSSStyleSelector::SelectorChecker::checkOneSelector): Added
     33            shadow descendant selector match check, since now there could be many
     34            of them in the selector chain.
     35
    1362011-04-20  Adrienne Walker  <enne@google.com>
    237
  • trunk/Source/WebCore/css/CSSGrammar.y

    r83415 r85077  
    980980        if (!$2)
    981981            $$ = 0;
    982         else if ($1) {
    983             CSSParser* p = static_cast<CSSParser*>(parser);
    984             CSSParserSelector* end;
    985             CSSParserSelector* history;
    986             // Ensure that unknown pseudo element always stays at the top of selector chain.
    987             if ($2->isUnknownPseudoElement()) {
    988                 end = $2;
    989                 history = $1;
    990             } else {
    991                 end = $1;
    992                 history = $2;
    993             }
    994             $$ = end;
    995             while(end->tagHistory())
    996                 end = end->tagHistory();
    997             end->setRelation(CSSSelector::SubSelector);
    998             end->setTagHistory(p->sinkFloatingSelector(history));
    999         }
     982        else if ($1)
     983            $$ = static_cast<CSSParser*>(parser)->updateSpecifiers($1, $2);
    1000984    }
    1001985    | specifier_list error {
  • trunk/Source/WebCore/css/CSSParser.cpp

    r84836 r85077  
    63706370    }
    63716371
    6372     specifiers->setRelation(CSSSelector::ShadowDescendant);
    6373     if (CSSParserSelector* history = specifiers->tagHistory()) {
    6374         history->setTag(tag);
     6372    CSSParserSelector* lastShadowDescendant = specifiers;
     6373    CSSParserSelector* history = specifiers;
     6374    while (history->tagHistory()) {
     6375        history = history->tagHistory();
     6376        if (history->hasShadowDescendant())
     6377            lastShadowDescendant = history;
     6378    }
     6379
     6380    if (lastShadowDescendant->tagHistory()) {
     6381        lastShadowDescendant->tagHistory()->setTag(tag);
    63756382        return;
    63766383    }
     
    63836390    CSSParserSelector* elementNameSelector = new CSSParserSelector;
    63846391    elementNameSelector->setTag(tag);
    6385     specifiers->setTagHistory(elementNameSelector);
    6386 }
    6387 
     6392    lastShadowDescendant->setTagHistory(elementNameSelector);
     6393    lastShadowDescendant->setRelation(CSSSelector::ShadowDescendant);
     6394}
     6395
     6396CSSParserSelector* CSSParser::updateSpecifiers(CSSParserSelector* specifiers, CSSParserSelector* newSpecifier)
     6397{
     6398    if (newSpecifier->isUnknownPseudoElement()) {
     6399        // Unknown pseudo element always goes at the top of selector chain.
     6400        newSpecifier->appendTagHistory(CSSSelector::ShadowDescendant, sinkFloatingSelector(specifiers));
     6401        return newSpecifier;
     6402    }
     6403    if (specifiers->isUnknownPseudoElement()) {
     6404        // Specifiers for unknown pseudo element go right behind it in the chain.
     6405        specifiers->insertTagHistory(CSSSelector::SubSelector, sinkFloatingSelector(newSpecifier), CSSSelector::ShadowDescendant);
     6406        return specifiers;
     6407    }
     6408    specifiers->appendTagHistory(CSSSelector::SubSelector, sinkFloatingSelector(newSpecifier));
     6409    return specifiers;
     6410}
    63886411
    63896412CSSRule* CSSParser::createPageRule(PassOwnPtr<CSSParserSelector> pageSelector)
  • trunk/Source/WebCore/css/CSSParser.h

    r83122 r85077  
    221221        void addNamespace(const AtomicString& prefix, const AtomicString& uri);
    222222        void updateSpecifiersWithElementName(const AtomicString& namespacePrefix, const AtomicString& elementName, CSSParserSelector*);
     223        CSSParserSelector* updateSpecifiers(CSSParserSelector*, CSSParserSelector*);
    223224
    224225        void invalidBlockHit();
  • trunk/Source/WebCore/css/CSSParserValues.cpp

    r83415 r85077  
    115115    m_selector->setSelectorList(adoptPtr(selectorList));
    116116}
     117
     118void CSSParserSelector::insertTagHistory(CSSSelector::Relation before, PassOwnPtr<CSSParserSelector> selector, CSSSelector::Relation after)
     119{
     120    if (m_tagHistory)
     121        selector->setTagHistory(m_tagHistory.release());
     122    setRelation(before);
     123    selector->setRelation(after);
     124    m_tagHistory = selector;
    117125}
    118126
     127void CSSParserSelector::appendTagHistory(CSSSelector::Relation relation, PassOwnPtr<CSSParserSelector> selector)
     128{
     129    CSSParserSelector* end = this;
     130    while (end->tagHistory())
     131        end = end->tagHistory();
     132    end->setRelation(relation);
     133    end->setTagHistory(selector);
     134}
     135
     136}
     137
  • trunk/Source/WebCore/css/CSSParserValues.h

    r83415 r85077  
    117117    bool isUnknownPseudoElement() const { return m_selector->isUnknownPseudoElement(); }
    118118    bool isSimple() const { return !m_tagHistory && m_selector->isSimple(); }
     119    bool hasShadowDescendant() const;
    119120
    120121    CSSParserSelector* tagHistory() const { return m_tagHistory.get(); }
    121122    void setTagHistory(PassOwnPtr<CSSParserSelector> selector) { m_tagHistory = selector; }
     123    void insertTagHistory(CSSSelector::Relation before, PassOwnPtr<CSSParserSelector>, CSSSelector::Relation after);
     124    void appendTagHistory(CSSSelector::Relation, PassOwnPtr<CSSParserSelector>);
    122125
    123126private:
     
    126129};
    127130
     131inline bool CSSParserSelector::hasShadowDescendant() const
     132{
     133    return m_selector->relation() == CSSSelector::ShadowDescendant;
     134}
     135
    128136}
    129137
  • trunk/Source/WebCore/css/CSSStyleSelector.cpp

    r85027 r85077  
    29672967            return false;
    29682968
    2969         if (sel->isUnknownPseudoElement())
     2969        if (sel->isUnknownPseudoElement()) {
    29702970            m_hasUnknownPseudoElements = true;
     2971            return e->shadowPseudoId() == sel->value();
     2972        }
    29712973
    29722974        PseudoId pseudoId = CSSSelector::pseudoId(sel->pseudoType());
Note: See TracChangeset for help on using the changeset viewer.