Changeset 30069 in webkit


Ignore:
Timestamp:
Feb 7, 2008 12:13:24 PM (16 years ago)
Author:
hyatt@apple.com
Message:

Fix for bug 6248, implement the nth-* CSS3 selectors. Patch based on original KHTML work from Allan Jensen
and improved upon by Nick Shanks.

Reviewed by Eric

  • css/CSSGrammar.y:
  • css/CSSParser.cpp: (WebCore::CSSParser::lex):
  • css/CSSSelector.cpp: (WebCore::CSSSelector::extractPseudoType):
  • css/CSSSelector.h: (WebCore::CSSSelector::):
  • css/CSSStyleSelector.cpp: (WebCore::parseNth): (WebCore::matchNth): (WebCore::CSSStyleSelector::checkOneSelector):
  • css/tokenizer.flex:
  • rendering/RenderStyle.cpp: (WebCore::RenderStyle::RenderStyle):
  • rendering/RenderStyle.h: (WebCore::RenderStyle::childIndex): (WebCore::RenderStyle::setChildIndex):
Location:
trunk/WebCore
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebCore/ChangeLog

    r30067 r30069  
     12008-02-07  David Hyatt  <hyatt@apple.com>
     2
     3        Fix for bug 6248, implement the nth-* CSS3 selectors.  Patch based on original KHTML work from Allan Jensen
     4        and improved upon by Nick Shanks.
     5
     6        Reviewed by Eric
     7
     8        * css/CSSGrammar.y:
     9        * css/CSSParser.cpp:
     10        (WebCore::CSSParser::lex):
     11        * css/CSSSelector.cpp:
     12        (WebCore::CSSSelector::extractPseudoType):
     13        * css/CSSSelector.h:
     14        (WebCore::CSSSelector::):
     15        * css/CSSStyleSelector.cpp:
     16        (WebCore::parseNth):
     17        (WebCore::matchNth):
     18        (WebCore::CSSStyleSelector::checkOneSelector):
     19        * css/tokenizer.flex:
     20        * rendering/RenderStyle.cpp:
     21        (WebCore::RenderStyle::RenderStyle):
     22        * rendering/RenderStyle.h:
     23        (WebCore::RenderStyle::childIndex):
     24        (WebCore::RenderStyle::setChildIndex):
     25
    1262008-02-07  Dan Bernstein  <mitz@apple.com>
    227
  • trunk/WebCore/css/CSSGrammar.y

    r29976 r30069  
    166166
    167167%token <string> STRING
    168 
    169168%right <string> IDENT
     169%token <string> NTH
    170170
    171171%nonassoc <string> HEX
     
    908908        }
    909909    }
    910     // used by :lang
     910    // used by :nth-*(ax+b)
     911    | ':' FUNCTION NTH ')' {
     912        CSSParser *p = static_cast<CSSParser*>(parser);
     913        $$ = p->createFloatingSelector();
     914        $$->m_match = CSSSelector::PseudoClass;
     915        $$->m_argument = atomicString($3);
     916        $$->m_value = atomicString($2);
     917        CSSSelector::PseudoType type = $$->pseudoType();
     918        if (type == CSSSelector::PseudoUnknown)
     919            $$ = 0;
     920        else if (type == CSSSelector::PseudoNthChild || type == CSSSelector::PseudoNthOfType) {
     921            if (p->document())
     922                p->document()->setUsesSiblingRules(true);
     923        }
     924    }
     925    // used by :nth-*
     926    | ':' FUNCTION INTEGER ')' {
     927        CSSParser *p = static_cast<CSSParser*>(parser);
     928        $$ = p->createFloatingSelector();
     929        $$->m_match = CSSSelector::PseudoClass;
     930        $$->m_argument = String::number($3);
     931        $$->m_value = atomicString($2);
     932        CSSSelector::PseudoType type = $$->pseudoType();
     933        if (type == CSSSelector::PseudoUnknown)
     934            $$ = 0;
     935        else if (type == CSSSelector::PseudoNthChild || type == CSSSelector::PseudoNthOfType) {
     936            if (p->document())
     937                p->document()->setUsesSiblingRules(true);
     938        }
     939    }
     940    // used by :nth-*(odd/even) and :lang
    911941    | ':' FUNCTION IDENT ')' {
    912         $$ = static_cast<CSSParser*>(parser)->createFloatingSelector();
     942        CSSParser *p = static_cast<CSSParser*>(parser);
     943        $$ = p->createFloatingSelector();
    913944        $$->m_match = CSSSelector::PseudoClass;
    914945        $$->m_argument = atomicString($3);
    915946        $2.lower();
    916947        $$->m_value = atomicString($2);
    917         if ($$->pseudoType() == CSSSelector::PseudoUnknown)
     948        CSSSelector::PseudoType type = $$->pseudoType();
     949        if (type == CSSSelector::PseudoUnknown)
    918950            $$ = 0;
     951        else if (type == CSSSelector::PseudoNthChild || type == CSSSelector::PseudoNthOfType) {
     952            if (p->document())
     953                p->document()->setUsesSiblingRules(true);
     954        }
    919955    }
    920956    // used by :not
  • trunk/WebCore/css/CSSParser.cpp

    r29910 r30069  
    35623562    case STRING:
    35633563    case IDENT:
     3564    case NTH:
    35643565    case HEX:
    35653566    case IDSEL:
  • trunk/WebCore/css/CSSSelector.cpp

    r29944 r30069  
    8585    static AtomicString firstLine("first-line");
    8686    static AtomicString firstOfType("first-of-type");
     87    static AtomicString nthChild("nth-child(");
     88    static AtomicString nthOfType("nth-of-type(");
     89    static AtomicString nthLastChild("nth-last-child(");
     90    static AtomicString nthLastOfType("nth-last-of-type(");
    8791    static AtomicString focus("focus");
    8892    static AtomicString hover("hover");
     
    200204    } else if (m_value == notStr)
    201205        m_pseudoType = PseudoNot;
     206    else if (m_value == nthChild)
     207        m_pseudoType = PseudoNthChild;
     208    else if (m_value == nthOfType)
     209        m_pseudoType = PseudoNthOfType;
     210    else if (m_value == nthLastChild)
     211        m_pseudoType = PseudoNthLastChild;
     212    else if (m_value == nthLastOfType)
     213        m_pseudoType = PseudoNthLastOfType;
    202214    else if (m_value == root)
    203215        m_pseudoType = PseudoRoot;
  • trunk/WebCore/css/CSSSelector.h

    r29944 r30069  
    128128            PseudoFirstLine,
    129129            PseudoFirstLetter,
     130            PseudoNthChild,
     131            PseudoNthOfType,
     132            PseudoNthLastChild,
     133            PseudoNthLastOfType,
    130134            PseudoLink,
    131135            PseudoVisited,
  • trunk/WebCore/css/CSSStyleSelector.cpp

    r29944 r30069  
    713713        ? PseudoVisited : PseudoLink;
    714714}
     715
     716// a helper function for parsing nth-arguments
     717static bool parseNth(const String& nth, int &a, int &b)
     718{
     719    if (nth.isEmpty())
     720        return false;
     721    a = 0;
     722    b = 0;
     723    if (nth == "odd") {
     724        a = 2;
     725        b = 1;
     726    } else if (nth == "even") {
     727        a = 2;
     728        b = 0;
     729    } else {
     730        int n = nth.find('n');
     731        if (n != -1) {
     732            if (nth[0] == '-') {
     733                if (n == 1)
     734                    a = -1; // -n == -1n
     735                else
     736                    a = nth.substring(1, n - 1).toInt();
     737            } else if (!n)
     738                a = 1; // n == 1n
     739            else
     740                a = nth.substring(0, n).toInt();
     741
     742            int p = nth.find('+', n);
     743            if (p != -1)
     744                b = nth.substring(p + 1, nth.length() - p - 1).toInt();
     745            else {
     746                p = nth.find('-', n);
     747                b = -nth.substring(p + 1, nth.length() - p - 1).toInt();
     748            }
     749        } else
     750            b = nth.toInt();
     751    }
     752    return true;
     753}
     754
     755// a helper function for checking nth-arguments
     756static bool matchNth(int count, int a, int b)
     757{
     758    if (!a)
     759        return count == b;
     760    else if (a > 0) {
     761        if (count < b)
     762            return false;
     763        return (count - b) % a == 0;
     764    } else {
     765        if (count > b)
     766            return false;
     767        return (b - count) % (-a) == 0;
     768    }
     769}
     770
    715771
    716772#ifdef STYLE_SHARING_STATS
     
    17221778            }
    17231779            case CSSSelector::PseudoOnlyOfType: {
     1780                // FIXME: This selector is very slow.
    17241781                if (e->parentNode() && e->parentNode()->isElementNode()) {
    17251782                    bool firstChild = false;
     
    17501807                    }
    17511808                    return firstChild && lastChild;
     1809                }
     1810                break;
     1811            }
     1812            case CSSSelector::PseudoNthChild: {
     1813                int a, b;
     1814                // calculate a and b every time we run through checkOneSelector
     1815                // this should probably be saved after we calculate it once, but currently
     1816                // would require increasing the size of CSSSelector
     1817                if (!parseNth(sel->m_argument, a, b))
     1818                    break;
     1819                if (e->parentNode() && e->parentNode()->isElementNode()) {
     1820                    int count = 1;
     1821                    Node* n = e->previousSibling();
     1822                    while (n) {
     1823                        if (n->isElementNode()) {
     1824                            RenderStyle* s = n->renderStyle();
     1825                            unsigned index = s ? s->childIndex() : 0;
     1826                            if (index) {
     1827                                count += index;
     1828                                break;
     1829                            }
     1830                            count++;
     1831                        }
     1832                        n = n->previousSibling();
     1833                    }
     1834                   
     1835                    if (!m_collectRulesOnly) {
     1836                        RenderStyle* childStyle = (m_element == e) ? m_style : e->renderStyle();
     1837                        RenderStyle* parentStyle = (m_element == e) ? m_parentStyle : e->parentNode()->renderStyle();
     1838                        if (childStyle)
     1839                            childStyle->setChildIndex(count);
     1840                        if (parentStyle)
     1841                            parentStyle->setChildrenAffectedByPositionalRules();
     1842                    }
     1843                   
     1844                    if (matchNth(count, a, b))
     1845                        return true;
     1846                }
     1847                break;
     1848            }
     1849            case CSSSelector::PseudoNthOfType: {
     1850                // FIXME: This selector is very slow.
     1851                int a, b;
     1852                // calculate a and b every time we run through checkOneSelector (see above)
     1853                if (!parseNth(sel->m_argument, a, b))
     1854                    break;
     1855                if (e->parentNode() && e->parentNode()->isElementNode()) {
     1856                    int count = 1;
     1857                    const QualifiedName& type = e->tagQName();
     1858                    Node* n = e->previousSibling();
     1859                    while (n) {
     1860                        if (n->isElementNode() && static_cast<Element*>(n)->hasTagName(type))
     1861                            count++;
     1862                        n = n->previousSibling();
     1863                    }
     1864                   
     1865                    if (!m_collectRulesOnly) {
     1866                        RenderStyle* parentStyle = (m_element == e) ? m_parentStyle : e->parentNode()->renderStyle();
     1867                        if (parentStyle)
     1868                            parentStyle->setChildrenAffectedByPositionalRules();
     1869                    }
     1870
     1871                    if (matchNth(count, a, b))
     1872                        return true;
     1873                }
     1874                break;
     1875            }
     1876            case CSSSelector::PseudoNthLastChild: {
     1877                int a, b;
     1878                // calculate a and b every time we run through checkOneSelector
     1879                // this should probably be saved after we calculate it once, but currently
     1880                // would require increasing the size of CSSSelector
     1881                if (!parseNth(sel->m_argument, a, b))
     1882                    break;
     1883                if (e->parentNode() && e->parentNode()->isElementNode()) {
     1884                    int count = 1;
     1885                    Node* n = e->nextSibling();
     1886                    while (n) {
     1887                        if (n->isElementNode())
     1888                            count++;
     1889                        n = n->nextSibling();
     1890                    }
     1891                   
     1892                    if (!m_collectRulesOnly) {
     1893                        RenderStyle* parentStyle = (m_element == e) ? m_parentStyle : e->parentNode()->renderStyle();
     1894                        if (parentStyle)
     1895                            parentStyle->setChildrenAffectedByPositionalRules();
     1896                    }
     1897                   
     1898                    if (matchNth(count, a, b))
     1899                        return true;
     1900                }
     1901                break;
     1902            }
     1903            case CSSSelector::PseudoNthLastOfType: {
     1904                // FIXME: This selector is very slow.
     1905                int a, b;
     1906                // calculate a and b every time we run through checkOneSelector (see above)
     1907                if (!parseNth(sel->m_argument, a, b))
     1908                    break;
     1909                if (e->parentNode() && e->parentNode()->isElementNode()) {
     1910                    int count = 1;
     1911                    const QualifiedName& type = e->tagQName();
     1912                    Node* n = e->nextSibling();
     1913                    while (n) {
     1914                        if (n->isElementNode() && static_cast<Element*>(n)->hasTagName(type))
     1915                            count++;
     1916                        n = n->nextSibling();
     1917                    }
     1918                   
     1919                    if (!m_collectRulesOnly) {
     1920                        RenderStyle* parentStyle = (m_element == e) ? m_parentStyle : e->parentNode()->renderStyle();
     1921                        if (parentStyle)
     1922                            parentStyle->setChildrenAffectedByPositionalRules();
     1923                    }
     1924
     1925                    if (matchNth(count, a, b))
     1926                        return true;
    17521927                }
    17531928                break;
  • trunk/WebCore/css/tokenizer.flex

    r25934 r30069  
    2424nl              \n|\r\n|\r|\f
    2525range           \?{1,6}|{h}(\?{0,5}|{h}(\?{0,4}|{h}(\?{0,3}|{h}(\?{0,2}|{h}(\??|{h})))))
     26nth             (-?[0-9]*n[\+-][0-9]+)|(-?[0-9]*n)
    2627
    2728%%
     
    4344
    4445{string}                {yyTok = STRING; return yyTok;}
    45 
    4646{ident}                 {yyTok = IDENT; return yyTok;}
     47{nth}                   {yyTok = NTH; return yyTok;}
    4748
    4849"#"{hexcolor}           {yyTok = HEX; return yyTok;}
  • trunk/WebCore/rendering/RenderStyle.cpp

    r29932 r30069  
    938938    , m_firstChildState(false)
    939939    , m_lastChildState(false)
     940    , m_childIndex(0)
    940941    , m_ref(0)
    941942#if ENABLE(SVG)
     
    958959    , m_firstChildState(false)
    959960    , m_lastChildState(false)
     961    , m_childIndex(0)
    960962    , m_ref(1)
    961963{
     
    10001002    , m_firstChildState(false)
    10011003    , m_lastChildState(false)
     1004    , m_childIndex(0)
    10021005    , m_ref(0)
    10031006#if ENABLE(SVG)
  • trunk/WebCore/rendering/RenderStyle.h

    r29932 r30069  
    14621462// list of associated pseudo styles
    14631463    RenderStyle* pseudoStyle;
    1464    
     1464
    14651465    unsigned m_pseudoState : 3; // PseudoState
    14661466    bool m_affectedByAttributeSelectors : 1;
     
    14781478    bool m_firstChildState : 1;
    14791479    bool m_lastChildState : 1;
     1480    unsigned m_childIndex : 20; // Plenty of bits to cache an index.
    14801481
    14811482    int m_ref;
     
    21352136    bool lastChildState() const { return m_lastChildState; }
    21362137    void setLastChildState() { m_lastChildState = true; }
     2138    unsigned childIndex() const { return m_childIndex; }
     2139    void setChildIndex(unsigned index) { m_childIndex = index; }
    21372140
    21382141    // Initial values for all the properties
Note: See TracChangeset for help on using the changeset viewer.