Implement sharing of similar style objects. Cuts the # of style objects allocated on the PLT by more
	than half.

        Reviewed by kocienda

        * khtml/css/cssstyleselector.cpp:
        (khtml::CSSStyleSelector::initElementAndPseudoState):
        (khtml::CSSStyleSelector::initForStyleResolve):
        (khtml::cleanpath):
        (khtml::checkPseudoState):
        (khtml::CSSStyleSelector::locateSiblingList):
        (khtml::CSSStyleSelector::canShareStyleWithElement):
        (khtml::CSSStyleSelector::locateSharedStyle):
        (khtml::CSSStyleSelector::styleForElement):
        (khtml::CSSStyleSelector::pseudoStyleForElement):
        (khtml::CSSStyleSelector::checkOneSelector):
        * khtml/css/cssstyleselector.h:
        * khtml/css/html4.css:
        * khtml/css/parser.cpp:
        * khtml/css/parser.y:
        * khtml/html/html_baseimpl.cpp:
        (HTMLBodyElementImpl::mapToEntry):
        (HTMLIFrameElementImpl::mapToEntry):
        * khtml/html/html_baseimpl.h:
        * khtml/html/html_blockimpl.cpp:
        (HTMLDivElementImpl::mapToEntry):
        (HTMLHRElementImpl::mapToEntry):
        (HTMLParagraphElementImpl::mapToEntry):
        (HTMLMarqueeElementImpl::mapToEntry):
        * khtml/html/html_blockimpl.h:
        * khtml/html/html_elementimpl.cpp:
        (HTMLNamedAttrMapImpl::declCount):
        (HTMLNamedAttrMapImpl::mapsEquivalent):
        (HTMLElementImpl::attributeChanged):
        (HTMLElementImpl::mapToEntry):
        * khtml/html/html_elementimpl.h:
        (DOM::HTMLElementImpl::isMappedAttribute):
        * khtml/html/html_formimpl.cpp:
        (HTMLInputElementImpl::mapToEntry):
        * khtml/html/html_formimpl.h:
        * khtml/html/html_imageimpl.cpp:
        (HTMLImageElementImpl::mapToEntry):
        * khtml/html/html_imageimpl.h:
        * khtml/html/html_inlineimpl.cpp:
        (HTMLBRElementImpl::mapToEntry):
        (HTMLFontElementImpl::mapToEntry):
        * khtml/html/html_inlineimpl.h:
        * khtml/html/html_listimpl.cpp:
        (HTMLUListElementImpl::mapToEntry):
        (HTMLOListElementImpl::mapToEntry):
        (HTMLLIElementImpl::mapToEntry):
        * khtml/html/html_listimpl.h:
        * khtml/html/html_objectimpl.cpp:
        (HTMLAppletElementImpl::mapToEntry):
        (HTMLEmbedElementImpl::mapToEntry):
        (HTMLObjectElementImpl::mapToEntry):
        * khtml/html/html_objectimpl.h:
        * khtml/html/html_tableimpl.cpp:
        (HTMLTableElementImpl::mapToEntry):
        (HTMLTablePartElementImpl::mapToEntry):
        (HTMLTableCellElementImpl::mapToEntry):
        (HTMLTableColElementImpl::mapToEntry):
        (HTMLTableCaptionElementImpl::mapToEntry):
        * khtml/html/html_tableimpl.h:
        * khtml/rendering/render_object.cpp:
        (RenderObject::setStyle):
        * khtml/rendering/render_style.cpp:
        (m_affectedByAttributeSelectors):
        (RenderStyle::RenderStyle):
        * khtml/rendering/render_style.h:
        (khtml::):
        (khtml::RenderStyle::pseudoState):
        (khtml::RenderStyle::setPseudoState):
        (khtml::RenderStyle::affectedByAttributeSelectors):
        (khtml::RenderStyle::setAffectedByAttributeSelectors):
        * khtml/xml/dom_docimpl.cpp:
        (DocumentImpl::DocumentImpl):
        * khtml/xml/dom_docimpl.h:
        (DOM::DocumentImpl::usesSiblingRules):
        (DOM::DocumentImpl::setUsesSiblingRules):


git-svn-id: svn://svn.chromium.org/blink/trunk@6514 bbb929c8-8fbe-4397-9dbb-9b2b20218538
diff --git a/WebCore/khtml/css/cssstyleselector.cpp b/WebCore/khtml/css/cssstyleselector.cpp
index d974928..8786556 100644
--- a/WebCore/khtml/css/cssstyleselector.cpp
+++ b/WebCore/khtml/css/cssstyleselector.cpp
@@ -115,11 +115,8 @@
 CSSStyleSheetImpl *CSSStyleSelector::quirksSheet = 0;
 
 static CSSStyleSelector::Encodedurl *encodedurl = 0;
-
-enum PseudoState { PseudoUnknown, PseudoNone, PseudoAnyLink, PseudoLink, PseudoVisited};
 static PseudoState pseudoState;
 
-
 CSSStyleSelector::CSSStyleSelector( DocumentImpl* doc, QString userStyleSheet, StyleSheetListImpl *styleSheets,
                                     const KURL &url, bool _strictParsing )
 {
@@ -405,18 +402,21 @@
     }    
 }
 
-void CSSStyleSelector::initForStyleResolve(ElementImpl* e, RenderStyle* defaultParent)
+void CSSStyleSelector::initElementAndPseudoState(ElementImpl* e)
 {
-    // set some variables we will need
-    ::encodedurl = &encodedurl;
-    pseudoState = PseudoUnknown;
-    pseudoStyle = RenderStyle::NOPSEUDO;
-    
     element = e;
     if (element && element->isHTMLElement())
         htmlElement = static_cast<HTMLElementImpl*>(element);
     else
         htmlElement = 0;
+    ::encodedurl = &encodedurl;
+    pseudoState = PseudoUnknown;
+}
+
+void CSSStyleSelector::initForStyleResolve(ElementImpl* e, RenderStyle* defaultParent)
+{
+    // set some variables we will need
+    pseudoStyle = RenderStyle::NOPSEUDO;
 
     parentNode = e->parentNode();
     if (defaultParent)
@@ -438,6 +438,195 @@
     fontDirty = false;
 }
 
+// modified version of the one in kurl.cpp
+static void cleanpath(QString &path)
+{
+    int pos;
+    while ( (pos = path.find( "/../" )) != -1 ) {
+        int prev = 0;
+        if ( pos > 0 )
+            prev = path.findRev( "/", pos -1 );
+        // don't remove the host, i.e. http://foo.org/../foo.html
+        if (prev < 0 || (prev > 3 && path.findRev("://", prev-1) == prev-2))
+            path.remove( pos, 3);
+        else
+            // matching directory found ?
+            path.remove( prev, pos- prev + 3 );
+    }
+    pos = 0;
+    
+    // Don't remove "//" from an anchor identifier. -rjw
+    // Set refPos to -2 to mean "I haven't looked for the anchor yet".
+    // We don't want to waste a function call on the search for the the anchor
+    // in the vast majority of cases where there is no "//" in the path.
+    int refPos = -2;
+    while ( (pos = path.find( "//", pos )) != -1) {
+        if (refPos == -2)
+            refPos = path.find("#", 0);
+        if (refPos > 0 && pos >= refPos)
+            break;
+        
+        if ( pos == 0 || path[pos-1] != ':' )
+            path.remove( pos, 1 );
+        else
+            pos += 2;
+    }
+    while ( (pos = path.find( "/./" )) != -1)
+        path.remove( pos, 2 );
+    //kdDebug() << "checkPseudoState " << path << endl;
+}
+
+static void checkPseudoState( DOM::ElementImpl *e, bool checkVisited = true )
+{
+    if (!e->hasAnchor()) {
+        pseudoState = PseudoNone;
+        return;
+    }
+    
+    const AtomicString& attr = e->getAttribute(ATTR_HREF);
+    if (attr.isNull()) {
+        pseudoState = PseudoNone;
+        return;
+    }
+    
+    if (!checkVisited) {
+        pseudoState = PseudoAnyLink;
+        return;
+    }
+    
+    QConstString cu(attr.unicode(), attr.length());
+    QString u = cu.string();
+    if ( !u.contains("://") ) {
+        if ( u[0] == '/' )
+            u.prepend(encodedurl->host);
+        else if ( u[0] == '#' )
+            u.prepend(encodedurl->file);
+        else
+            u.prepend(encodedurl->path);
+        cleanpath( u );
+    }
+    //completeURL( attr.string() );
+    pseudoState = KHTMLFactory::vLinks()->contains( u ) ? PseudoVisited : PseudoLink;
+}
+
+#ifdef STYLE_SHARING_STATS
+static int fraction = 0;
+static int total = 0;
+#endif
+
+const int siblingThreshold = 10;
+
+NodeImpl* CSSStyleSelector::locateCousinList(ElementImpl* parent)
+{
+    if (parent && parent->isHTMLElement()) {
+        HTMLElementImpl* p = static_cast<HTMLElementImpl*>(parent);
+        if (p->renderer() && !p->inlineStyleDecl() && !p->hasID()) {
+            DOM::NodeImpl* r = p->previousSibling();
+            int subcount = 0;
+            RenderStyle* st = p->renderer()->style();
+            while (r) {
+                if (r->renderer() && r->renderer()->style() == st)
+                    return r->lastChild();
+                if (subcount++ == siblingThreshold)
+                    return 0;
+                r = r->previousSibling();
+            }
+            if (!r)
+                r = locateCousinList(static_cast<ElementImpl*>(parent->parentNode()));
+            while (r) {
+                if (r->renderer() && r->renderer()->style() == st)
+                    return r->lastChild();
+                if (subcount++ == siblingThreshold)
+                    return 0;
+                r = r->previousSibling();
+            }
+        }
+    }
+    return 0;
+}
+
+bool CSSStyleSelector::canShareStyleWithElement(NodeImpl* n)
+{
+    if (n->isHTMLElement()) {
+        bool mouseInside = element->renderer() ? element->renderer()->mouseInside() : false;
+        HTMLElementImpl* s = static_cast<HTMLElementImpl*>(n);
+        if (s->renderer() && (s->id() == element->id()) && !s->hasID() &&
+            (s->hasClass() == element->hasClass()) && !s->inlineStyleDecl() &&
+            (s->hasMappedAttributes() == htmlElement->hasMappedAttributes()) &&
+            (s->hasAnchor() == element->hasAnchor()) && 
+            !s->renderer()->style()->affectedByAttributeSelectors() &&
+            (s->renderer()->mouseInside() == mouseInside) &&
+            (s->active() == element->active()) &&
+            (s->focused() == element->focused())) {
+            bool classesMatch = true;
+            if (s->hasClass()) {
+                const AtomicString& class1 = element->getAttribute(ATTR_CLASS);
+                const AtomicString& class2 = s->getAttribute(ATTR_CLASS);
+                classesMatch = (class1 == class2);
+            }
+            
+            if (classesMatch) {
+                bool mappedAttrsMatch = true;
+                if (s->hasMappedAttributes())
+                    mappedAttrsMatch = s->htmlAttributes()->mapsEquivalent(htmlElement->htmlAttributes());
+                if (mappedAttrsMatch) {
+                    bool anchorsMatch = true;
+                    if (s->hasAnchor()) {
+                        // We need to check to see if the visited state matches.
+                        QColor linkColor = element->getDocument()->linkColor();
+                        QColor visitedColor = element->getDocument()->visitedLinkColor();
+                        if (pseudoState == PseudoUnknown)
+                            checkPseudoState(s, s->renderer()->style()->pseudoState() != PseudoAnyLink ||
+                                             linkColor != visitedColor);
+                        anchorsMatch = (pseudoState == s->renderer()->style()->pseudoState());
+                    }
+                    
+                    if (anchorsMatch) {
+#ifdef STYLE_SHARING_STATS
+                        fraction++;
+                        printf("Sharing %d out of %d\n", fraction, total);
+#endif
+                        return true;
+                    }
+                }
+            }
+        }
+    }
+    return false;
+}
+
+RenderStyle* CSSStyleSelector::locateSharedStyle()
+{
+    //total++;
+    if (htmlElement && !htmlElement->inlineStyleDecl() && !htmlElement->hasID() &&
+        !htmlElement->getDocument()->usesSiblingRules()) {
+        // Check previous siblings.
+        int count = 0;
+        DOM::NodeImpl* n;
+        for (n = element->previousSibling(); n && !n->isElementNode(); n = n->previousSibling());
+        while (n) {
+            if (canShareStyleWithElement(n))
+                return n->renderer()->style();
+            if (count++ == siblingThreshold)
+                return 0;
+            for (n = n->previousSibling(); n && !n->isElementNode(); n = n->previousSibling());
+        }
+        if (!n) 
+            n = locateCousinList(static_cast<ElementImpl*>(element->parentNode()));
+        while (n) {
+            if (canShareStyleWithElement(n))
+                return n->renderer()->style();
+            if (count++ == siblingThreshold)
+                return 0;
+            for (n = n->previousSibling(); n && !n->isElementNode(); n = n->previousSibling());
+        }        
+    }
+#ifdef STYLE_SHARING_STATS
+    printf("Sharing %d out of %d\n", fraction, total);
+#endif
+    return 0;
+}
+
 RenderStyle* CSSStyleSelector::styleForElement(ElementImpl* e, RenderStyle* defaultParent)
 {
     if (!e->getDocument()->haveStylesheetsLoaded()) {
@@ -449,6 +638,10 @@
         return styleNotYetAvailable;
     }
     
+    initElementAndPseudoState(e);
+    style = locateSharedStyle();
+    if (style)
+        return style;
     initForStyleResolve(e, defaultParent);
 
     style = new (e->getDocument()->renderArena()) RenderStyle();
@@ -548,6 +741,10 @@
     // Clean up our style object's display and text decorations (among other fixups).
     adjustRenderStyle(style, e);
 
+    // If we are a link, cache the determined pseudo-state.
+    if (e->hasAnchor())
+        style->setPseudoState(pseudoState);
+
     // Now return the style.
     return style;
 }
@@ -567,6 +764,7 @@
         return styleNotYetAvailable;
     }
     
+    initElementAndPseudoState(e);
     initForStyleResolve(e, parentStyle);
     pseudoStyle = pseudo;
     
@@ -701,77 +899,6 @@
 
 static bool subject;
 
-// modified version of the one in kurl.cpp
-static void cleanpath(QString &path)
-{
-    int pos;
-    while ( (pos = path.find( "/../" )) != -1 ) {
-        int prev = 0;
-        if ( pos > 0 )
-            prev = path.findRev( "/", pos -1 );
-        // don't remove the host, i.e. http://foo.org/../foo.html
-        if (prev < 0 || (prev > 3 && path.findRev("://", prev-1) == prev-2))
-            path.remove( pos, 3);
-        else
-            // matching directory found ?
-            path.remove( prev, pos- prev + 3 );
-    }
-    pos = 0;
-
-    // Don't remove "//" from an anchor identifier. -rjw
-    // Set refPos to -2 to mean "I haven't looked for the anchor yet".
-    // We don't want to waste a function call on the search for the the anchor
-    // in the vast majority of cases where there is no "//" in the path.
-    int refPos = -2;
-    while ( (pos = path.find( "//", pos )) != -1) {
-        if (refPos == -2)
-            refPos = path.find("#", 0);
-        if (refPos > 0 && pos >= refPos)
-            break;
-
-        if ( pos == 0 || path[pos-1] != ':' )
-            path.remove( pos, 1 );
-        else
-            pos += 2;
-    }
-    while ( (pos = path.find( "/./" )) != -1)
-        path.remove( pos, 2 );
-    //kdDebug() << "checkPseudoState " << path << endl;
-}
-
-static void checkPseudoState( DOM::ElementImpl *e, bool checkVisited = true )
-{
-    if (!e->hasAnchor()) {
-        pseudoState = PseudoNone;
-        return;
-    }
-
-    const AtomicString& attr = e->getAttribute(ATTR_HREF);
-    if (attr.isNull()) {
-        pseudoState = PseudoNone;
-        return;
-    }
-    
-    if (!checkVisited) {
-        pseudoState = PseudoAnyLink;
-        return;
-    }
-
-    QConstString cu(attr.unicode(), attr.length());
-    QString u = cu.string();
-    if ( !u.contains("://") ) {
-        if ( u[0] == '/' )
-            u.prepend(encodedurl->host);
-        else if ( u[0] == '#' )
-            u.prepend(encodedurl->file);
-        else
-            u.prepend(encodedurl->path);
-        cleanpath( u );
-    }
-    //completeURL( attr.string() );
-    pseudoState = KHTMLFactory::vLinks()->contains( u ) ? PseudoVisited : PseudoLink;
-}
-
 bool CSSStyleSelector::checkSelector(CSSSelector* sel, ElementImpl *e)
 {
     dynamicPseudo = RenderStyle::NOPSEUDO;
@@ -912,6 +1039,8 @@
         }
         else if (sel->match == CSSSelector::Id)
             return e->hasID() && e->getIDAttribute() == sel->value;
+        else if (e != element || !htmlElement || !htmlElement->isMappedAttribute(sel->attr))
+            style->setAffectedByAttributeSelectors();
 
         const AtomicString& value = e->getAttribute(sel->attr);
         if (value.isNull()) return false; // attribute is not set
diff --git a/WebCore/khtml/css/cssstyleselector.h b/WebCore/khtml/css/cssstyleselector.h
index 64f8b7f..6cd62eb 100644
--- a/WebCore/khtml/css/cssstyleselector.h
+++ b/WebCore/khtml/css/cssstyleselector.h
@@ -103,11 +103,16 @@
 
 	static void loadDefaultStyle(const KHTMLSettings *s = 0);
 
+        void initElementAndPseudoState(DOM::ElementImpl* e);
         void initForStyleResolve(DOM::ElementImpl* e, RenderStyle* parentStyle);
 	RenderStyle *styleForElement(DOM::ElementImpl* e, RenderStyle* parentStyle=0);
         RenderStyle* pseudoStyleForElement(RenderStyle::PseudoId pseudoStyle, 
                                            DOM::ElementImpl* e, RenderStyle* parentStyle=0);
 
+        RenderStyle* locateSharedStyle();
+        DOM::NodeImpl* locateCousinList(DOM::ElementImpl* parent);
+        bool canShareStyleWithElement(DOM::NodeImpl* e);
+        
 	bool strictParsing;
 	struct Encodedurl {
 	    QString host; //also contains protocol
diff --git a/WebCore/khtml/css/html4.css b/WebCore/khtml/css/html4.css
index f1d9b3e..a7d8aa8 100644
--- a/WebCore/khtml/css/html4.css
+++ b/WebCore/khtml/css/html4.css
@@ -170,9 +170,9 @@
 	border-color: gray;
 }
 
-TABLE[align="center"] { 
-    margin-left: auto; 
-    margin-right: auto;
+TABLE[align="center"] {
+        margin-left: auto;
+        margin-right: auto;
 }
 
 THEAD { 
@@ -231,14 +231,14 @@
         display: block;
         list-style-type: disc;
         margin: 1__qem 0 1em 0;
-        padding-left: 40px;
+        padding-left: 40px; /* For RTL, we need to implement padding-start */
 }
 
 OL {
         display: block;
         list-style-type: decimal;
         margin: 1__qem 0 1em 0;
-        padding-left: 40px;
+        padding-left: 40px; /* For RTL, we need to implement padding-start */
 }
 
 LI {
@@ -246,22 +246,18 @@
 }
 
 
-UL UL { 
+UL UL, OL UL { 
 	list-style-type: circle;
 }
 
-OL UL { 
-	list-style-type: circle;
-}
-
-UL UL UL { 
+OL OL UL, OL UL UL, UL OL UL, UL UL UL { 
 	list-style-type: square;
 }
       
 
 DD {
 	display: block;
-	margin-left: 40px;
+	margin-left: 40px; /* For RTL, we need to implement margin-start */
 }
 
 DL {
@@ -272,24 +268,13 @@
 DT {
 	display: block;
 }
- 
-/* for right to left */
-      
-*[dir="rtl"] UL, 
-*[dir="rtl"] OL,  
-*[dir="rtl"] DIR, 
-*[dir="rtl"] MENU, 
-*[dir="rtl"] DD { 
-	margin-right:40px; 
-	margin-left: auto;
-}
-      
+
 OL UL, 
 UL OL,
 UL UL, 
 OL OL { 
-	margin-top: auto; 
-	margin-bottom: auto; 
+	margin-top: 0; 
+	margin-bottom: 0; 
 }
 
 /*
@@ -437,12 +422,7 @@
 	direction: rtl; 
 	unicode-bidi: bidi-override;
 }
-
-/* ### this selector seems to be still broken ...
-      *[DIR="ltr"]    { direction: ltr; unicode-bidi: embed }
-      *[DIR="rtl"]    { direction: rtl; unicode-bidi: embed }
-*/
-      
+   
 /* Elements that are block-level in HTML4 */
 /* ### don't support unicode-bidi at the moment
       ADDRESS, BLOCKQUOTE, BODY, DD, DIV, DL, DT, FIELDSET,
diff --git a/WebCore/khtml/css/parser.cpp b/WebCore/khtml/css/parser.cpp
index 28ce175..e90a51c 100644
--- a/WebCore/khtml/css/parser.cpp
+++ b/WebCore/khtml/css/parser.cpp
@@ -311,17 +311,17 @@
    357,   362,   371,   372,   375,   377,   380,   382,   385,   389,
    393,   397,   401,   406,   412,   426,   428,   437,   459,   463,
    468,   472,   477,   479,   480,   483,   485,   488,   508,   520,
-   534,   540,   544,   567,   573,   575,   576,   579,   584,   589,
-   594,   601,   610,   621,   638,   643,   647,   657,   663,   673,
-   674,   675,   678,   690,   710,   716,   722,   730,   741,   745,
-   748,   751,   754,   757,   762,   764,   767,   774,   781,   790,
-   794,   799,   802,   808,   816,   820,   823,   829,   835,   840,
-   846,   854,   877,   881,   889,   894,   901,   908,   910,   913,
-   918,   931,   937,   941,   944,   949,   951,   952,   953,   960,
-   961,   962,   963,   964,   965,   967,   972,   974,   975,   976,
-   977,   978,   979,   980,   981,   982,   983,   984,   985,   986,
-   987,   988,   989,   990,   994,  1002,  1017,  1024,  1031,  1039,
-  1065,  1067,  1070,  1072
+   534,   540,   544,   573,   579,   581,   582,   585,   590,   595,
+   600,   607,   616,   627,   644,   649,   653,   663,   669,   679,
+   680,   681,   684,   696,   716,   722,   728,   736,   747,   751,
+   754,   757,   760,   763,   768,   770,   773,   787,   794,   803,
+   807,   812,   815,   821,   829,   833,   836,   842,   848,   853,
+   859,   867,   890,   894,   902,   907,   914,   921,   923,   926,
+   931,   944,   950,   954,   957,   962,   964,   965,   966,   973,
+   974,   975,   976,   977,   978,   980,   985,   987,   988,   989,
+   990,   991,   992,   993,   994,   995,   996,   997,   998,   999,
+  1000,  1001,  1002,  1003,  1007,  1015,  1030,  1037,  1044,  1052,
+  1078,  1080,  1083,  1085
 };
 #endif
 
@@ -1468,39 +1468,45 @@
                 if ( doc )
                     doc->setUsesDescendantRules(true);
             }
+            else if (yyvsp[-1].relation == CSSSelector::Sibling) {
+                CSSParser *p = static_cast<CSSParser *>(parser);
+                DOM::DocumentImpl *doc = p->document();
+                if (doc)
+                    doc->setUsesSiblingRules(true);
+            }
         } else {
             delete yyvsp[-2].selector;
         }
     ;
     break;}
 case 64:
-#line 567 "parser.y"
+#line 573 "parser.y"
 {
         delete yyvsp[-1].selector;
         yyval.selector = 0;
     ;
     break;}
 case 65:
-#line 574 "parser.y"
+#line 580 "parser.y"
 { yyval.string.string = 0; yyval.string.length = 0; ;
     break;}
 case 66:
-#line 575 "parser.y"
+#line 581 "parser.y"
 { static unsigned short star = '*'; yyval.string.string = &star; yyval.string.length = 1; ;
     break;}
 case 67:
-#line 576 "parser.y"
+#line 582 "parser.y"
 { yyval.string = yyvsp[0].string; ;
     break;}
 case 68:
-#line 580 "parser.y"
+#line 586 "parser.y"
 {
 	yyval.selector = new CSSSelector();
 	yyval.selector->tag = yyvsp[-1].element;
     ;
     break;}
 case 69:
-#line 584 "parser.y"
+#line 590 "parser.y"
 {
 	yyval.selector = yyvsp[-1].selector;
 	if ( yyval.selector )
@@ -1508,7 +1514,7 @@
     ;
     break;}
 case 70:
-#line 589 "parser.y"
+#line 595 "parser.y"
 {
 	yyval.selector = yyvsp[-1].selector;
         if (yyval.selector)
@@ -1516,7 +1522,7 @@
     ;
     break;}
 case 71:
-#line 594 "parser.y"
+#line 600 "parser.y"
 {
         yyval.selector = new CSSSelector();
         yyval.selector->tag = yyvsp[-1].element;
@@ -1526,7 +1532,7 @@
     ;
     break;}
 case 72:
-#line 601 "parser.y"
+#line 607 "parser.y"
 {
         yyval.selector = yyvsp[-1].selector;
         if (yyval.selector) {
@@ -1538,7 +1544,7 @@
     ;
     break;}
 case 73:
-#line 610 "parser.y"
+#line 616 "parser.y"
 {
         yyval.selector = yyvsp[-1].selector;
         if (yyval.selector) {
@@ -1550,7 +1556,7 @@
     ;
     break;}
 case 74:
-#line 622 "parser.y"
+#line 628 "parser.y"
 {
 	CSSParser *p = static_cast<CSSParser *>(parser);
 	DOM::DocumentImpl *doc = p->document();
@@ -1569,19 +1575,19 @@
     ;
     break;}
 case 75:
-#line 638 "parser.y"
+#line 644 "parser.y"
 {
 	yyval.element = makeId(static_cast<CSSParser*>(parser)->defaultNamespace, anyLocalName);
     ;
     break;}
 case 76:
-#line 644 "parser.y"
+#line 650 "parser.y"
 {
 	yyval.selector = yyvsp[0].selector;
     ;
     break;}
 case 77:
-#line 647 "parser.y"
+#line 653 "parser.y"
 {
 	yyval.selector = yyvsp[-1].selector;
         if (yyval.selector) {
@@ -1594,14 +1600,14 @@
     ;
     break;}
 case 78:
-#line 657 "parser.y"
+#line 663 "parser.y"
 {
         delete yyvsp[-1].selector;
         yyval.selector = 0;
     ;
     break;}
 case 79:
-#line 664 "parser.y"
+#line 670 "parser.y"
 {
 	yyval.selector = new CSSSelector();
 	yyval.selector->match = CSSSelector::Id;
@@ -1613,7 +1619,7 @@
     ;
     break;}
 case 83:
-#line 679 "parser.y"
+#line 685 "parser.y"
 {
         yyval.selector = new CSSSelector();
 	yyval.selector->match = CSSSelector::Class;
@@ -1625,7 +1631,7 @@
     ;
     break;}
 case 84:
-#line 691 "parser.y"
+#line 697 "parser.y"
 {
 	CSSParser *p = static_cast<CSSParser *>(parser);
 	DOM::DocumentImpl *doc = p->document();
@@ -1645,7 +1651,7 @@
     ;
     break;}
 case 85:
-#line 711 "parser.y"
+#line 717 "parser.y"
 {
 	yyval.selector = new CSSSelector();
 	yyval.selector->attr = yyvsp[-1].attribute;
@@ -1653,7 +1659,7 @@
     ;
     break;}
 case 86:
-#line 716 "parser.y"
+#line 722 "parser.y"
 {
 	yyval.selector = new CSSSelector();
 	yyval.selector->attr = yyvsp[-5].attribute;
@@ -1662,7 +1668,7 @@
     ;
     break;}
 case 87:
-#line 722 "parser.y"
+#line 728 "parser.y"
 {
         yyval.selector = new CSSSelector();
         yyval.selector->attr = yyvsp[-1].attribute;
@@ -1673,7 +1679,7 @@
     ;
     break;}
 case 88:
-#line 730 "parser.y"
+#line 736 "parser.y"
 {
         yyval.selector = new CSSSelector();
         yyval.selector->attr = yyvsp[-5].attribute;
@@ -1685,52 +1691,59 @@
     ;
     break;}
 case 89:
-#line 742 "parser.y"
+#line 748 "parser.y"
 {
 	yyval.val = CSSSelector::Exact;
     ;
     break;}
 case 90:
-#line 745 "parser.y"
+#line 751 "parser.y"
 {
 	yyval.val = CSSSelector::List;
     ;
     break;}
 case 91:
-#line 748 "parser.y"
+#line 754 "parser.y"
 {
 	yyval.val = CSSSelector::Hyphen;
     ;
     break;}
 case 92:
-#line 751 "parser.y"
+#line 757 "parser.y"
 {
 	yyval.val = CSSSelector::Begin;
     ;
     break;}
 case 93:
-#line 754 "parser.y"
+#line 760 "parser.y"
 {
 	yyval.val = CSSSelector::End;
     ;
     break;}
 case 94:
-#line 757 "parser.y"
+#line 763 "parser.y"
 {
 	yyval.val = CSSSelector::Contain;
     ;
     break;}
 case 97:
-#line 768 "parser.y"
+#line 774 "parser.y"
 {
         yyval.selector = new CSSSelector();
         yyval.selector->match = CSSSelector::Pseudo;
         yyvsp[0].string.lower();
         yyval.selector->value = atomicString(yyvsp[0].string);
+        if (yyval.selector->value == "empty" || yyval.selector->value == "only-child" ||
+            yyval.selector->value == "first-child" || yyval.selector->value == "last-child") {
+            CSSParser *p = static_cast<CSSParser *>(parser);
+            DOM::DocumentImpl *doc = p->document();
+            if (doc)
+                doc->setUsesSiblingRules(true);
+        }
     ;
     break;}
 case 98:
-#line 775 "parser.y"
+#line 788 "parser.y"
 {
         yyval.selector = new CSSSelector();
         yyval.selector->match = CSSSelector::Pseudo;
@@ -1739,7 +1752,7 @@
     ;
     break;}
 case 99:
-#line 781 "parser.y"
+#line 794 "parser.y"
 {
         yyval.selector = new CSSSelector();
         yyval.selector->match = CSSSelector::Pseudo;
@@ -1749,13 +1762,13 @@
     ;
     break;}
 case 100:
-#line 791 "parser.y"
+#line 804 "parser.y"
 {
 	yyval.ok = yyvsp[0].ok;
     ;
     break;}
 case 101:
-#line 794 "parser.y"
+#line 807 "parser.y"
 {
 	yyval.ok = yyvsp[-1].ok;
 	if ( yyvsp[0].ok )
@@ -1763,13 +1776,13 @@
     ;
     break;}
 case 102:
-#line 799 "parser.y"
+#line 812 "parser.y"
 {
 	yyval.ok = yyvsp[0].ok;
     ;
     break;}
 case 103:
-#line 802 "parser.y"
+#line 815 "parser.y"
 {
 	yyval.ok = false;
 #ifdef CSS_DEBUG
@@ -1778,7 +1791,7 @@
     ;
     break;}
 case 104:
-#line 808 "parser.y"
+#line 821 "parser.y"
 {
 	yyval.ok = false;
 #ifdef CSS_DEBUG
@@ -1787,19 +1800,19 @@
     ;
     break;}
 case 105:
-#line 817 "parser.y"
+#line 830 "parser.y"
 {
 	yyval.ok = yyvsp[-2].ok;
     ;
     break;}
 case 106:
-#line 820 "parser.y"
+#line 833 "parser.y"
 {
         yyval.ok = false;
     ;
     break;}
 case 107:
-#line 823 "parser.y"
+#line 836 "parser.y"
 {
 	yyval.ok = false;
 #ifdef CSS_DEBUG
@@ -1808,7 +1821,7 @@
     ;
     break;}
 case 108:
-#line 829 "parser.y"
+#line 842 "parser.y"
 {
 	yyval.ok = false;
 #ifdef CSS_DEBUG
@@ -1817,7 +1830,7 @@
     ;
     break;}
 case 109:
-#line 835 "parser.y"
+#line 848 "parser.y"
 {
 	yyval.ok = yyvsp[-3].ok;
 	if ( yyvsp[-2].ok )
@@ -1825,7 +1838,7 @@
     ;
     break;}
 case 110:
-#line 840 "parser.y"
+#line 853 "parser.y"
 {
 	yyval.ok = yyvsp[-3].ok;
 #ifdef CSS_DEBUG
@@ -1834,7 +1847,7 @@
     ;
     break;}
 case 111:
-#line 846 "parser.y"
+#line 859 "parser.y"
 {
 	yyval.ok = yyvsp[-5].ok;
 #ifdef CSS_DEBUG
@@ -1843,7 +1856,7 @@
     ;
     break;}
 case 112:
-#line 855 "parser.y"
+#line 868 "parser.y"
 {
 	yyval.ok = false;
 	CSSParser *p = static_cast<CSSParser *>(parser);
@@ -1868,13 +1881,13 @@
     ;
     break;}
 case 113:
-#line 878 "parser.y"
+#line 891 "parser.y"
 {
         yyval.ok = false;
     ;
     break;}
 case 114:
-#line 882 "parser.y"
+#line 895 "parser.y"
 {
         /* The default movable type template has letter-spacing: .none;  Handle this by looking for
         error tokens at the start of an expr, recover the expr and then treat as an error, cleaning
@@ -1884,43 +1897,43 @@
     ;
     break;}
 case 115:
-#line 890 "parser.y"
+#line 903 "parser.y"
 {
         /* Handle this case: div { text-align: center; !important } Just reduce away the stray !important. */
         yyval.ok = false;
     ;
     break;}
 case 116:
-#line 895 "parser.y"
+#line 908 "parser.y"
 {
         /* div { font-family: } Just reduce away this property with no value. */
         yyval.ok = false;
     ;
     break;}
 case 117:
-#line 902 "parser.y"
+#line 915 "parser.y"
 {
 	QString str = qString(yyvsp[-1].string);
 	yyval.prop_id = getPropertyID( str.lower().latin1(), str.length() );
     ;
     break;}
 case 118:
-#line 909 "parser.y"
+#line 922 "parser.y"
 { yyval.b = true; ;
     break;}
 case 119:
-#line 910 "parser.y"
+#line 923 "parser.y"
 { yyval.b = false; ;
     break;}
 case 120:
-#line 914 "parser.y"
+#line 927 "parser.y"
 {
 	yyval.valueList = new ValueList;
 	yyval.valueList->addValue( yyvsp[0].value );
     ;
     break;}
 case 121:
-#line 918 "parser.y"
+#line 931 "parser.y"
 {
         yyval.valueList = yyvsp[-2].valueList;
 	if ( yyval.valueList ) {
@@ -1936,44 +1949,44 @@
     ;
     break;}
 case 122:
-#line 931 "parser.y"
+#line 944 "parser.y"
 {
         delete yyvsp[-1].valueList;
         yyval.valueList = 0;
     ;
     break;}
 case 123:
-#line 938 "parser.y"
+#line 951 "parser.y"
 {
 	yyval.tok = '/';
     ;
     break;}
 case 124:
-#line 941 "parser.y"
+#line 954 "parser.y"
 {
 	yyval.tok = ',';
     ;
     break;}
 case 125:
-#line 944 "parser.y"
+#line 957 "parser.y"
 {
         yyval.tok = 0;
   ;
     break;}
 case 126:
-#line 950 "parser.y"
+#line 963 "parser.y"
 { yyval.value = yyvsp[0].value; ;
     break;}
 case 127:
-#line 951 "parser.y"
+#line 964 "parser.y"
 { yyval.value = yyvsp[0].value; yyval.value.fValue *= yyvsp[-1].val; ;
     break;}
 case 128:
-#line 952 "parser.y"
+#line 965 "parser.y"
 { yyval.value.id = 0; yyval.value.string = yyvsp[-1].string; yyval.value.unit = CSSPrimitiveValue::CSS_STRING; ;
     break;}
 case 129:
-#line 953 "parser.y"
+#line 966 "parser.y"
 {
       QString str = qString( yyvsp[-1].string );
       yyval.value.id = getValueID( str.lower().latin1(), str.length() );
@@ -1982,109 +1995,109 @@
   ;
     break;}
 case 130:
-#line 960 "parser.y"
+#line 973 "parser.y"
 { yyval.value.id = 0; yyval.value.string = yyvsp[-1].string; yyval.value.unit = CSSPrimitiveValue::CSS_DIMENSION ;
     break;}
 case 131:
-#line 961 "parser.y"
+#line 974 "parser.y"
 { yyval.value.id = 0; yyval.value.string = yyvsp[-1].string; yyval.value.unit = CSSPrimitiveValue::CSS_DIMENSION ;
     break;}
 case 132:
-#line 962 "parser.y"
+#line 975 "parser.y"
 { yyval.value.id = 0; yyval.value.string = yyvsp[-1].string; yyval.value.unit = CSSPrimitiveValue::CSS_URI; ;
     break;}
 case 133:
-#line 963 "parser.y"
+#line 976 "parser.y"
 { yyval.value.id = 0; yyval.value.iValue = 0; yyval.value.unit = CSSPrimitiveValue::CSS_UNKNOWN;/* ### */ ;
     break;}
 case 134:
-#line 964 "parser.y"
+#line 977 "parser.y"
 { yyval.value.id = 0; yyval.value.string = yyvsp[0].string; yyval.value.unit = CSSPrimitiveValue::CSS_RGBCOLOR; ;
     break;}
 case 135:
-#line 965 "parser.y"
+#line 978 "parser.y"
 { yyval.value.id = 0; yyval.value.string = ParseString(); yyval.value.unit = CSSPrimitiveValue::CSS_RGBCOLOR; ;
     break;}
 case 136:
-#line 967 "parser.y"
+#line 980 "parser.y"
 {
       yyval.value = yyvsp[0].value;
   ;
     break;}
 case 137:
-#line 973 "parser.y"
+#line 986 "parser.y"
 { yyval.value.id = 0; yyval.value.fValue = yyvsp[-1].val; yyval.value.unit = CSSPrimitiveValue::CSS_NUMBER; ;
     break;}
 case 138:
-#line 974 "parser.y"
+#line 987 "parser.y"
 { yyval.value.id = 0; yyval.value.fValue = yyvsp[-1].val; yyval.value.unit = CSSPrimitiveValue::CSS_PERCENTAGE; ;
     break;}
 case 139:
-#line 975 "parser.y"
+#line 988 "parser.y"
 { yyval.value.id = 0; yyval.value.fValue = yyvsp[-1].val; yyval.value.unit = CSSPrimitiveValue::CSS_PX; ;
     break;}
 case 140:
-#line 976 "parser.y"
+#line 989 "parser.y"
 { yyval.value.id = 0; yyval.value.fValue = yyvsp[-1].val; yyval.value.unit = CSSPrimitiveValue::CSS_CM; ;
     break;}
 case 141:
-#line 977 "parser.y"
+#line 990 "parser.y"
 { yyval.value.id = 0; yyval.value.fValue = yyvsp[-1].val; yyval.value.unit = CSSPrimitiveValue::CSS_MM; ;
     break;}
 case 142:
-#line 978 "parser.y"
+#line 991 "parser.y"
 { yyval.value.id = 0; yyval.value.fValue = yyvsp[-1].val; yyval.value.unit = CSSPrimitiveValue::CSS_IN; ;
     break;}
 case 143:
-#line 979 "parser.y"
+#line 992 "parser.y"
 { yyval.value.id = 0; yyval.value.fValue = yyvsp[-1].val; yyval.value.unit = CSSPrimitiveValue::CSS_PT; ;
     break;}
 case 144:
-#line 980 "parser.y"
+#line 993 "parser.y"
 { yyval.value.id = 0; yyval.value.fValue = yyvsp[-1].val; yyval.value.unit = CSSPrimitiveValue::CSS_PC; ;
     break;}
 case 145:
-#line 981 "parser.y"
+#line 994 "parser.y"
 { yyval.value.id = 0; yyval.value.fValue = yyvsp[-1].val; yyval.value.unit = CSSPrimitiveValue::CSS_DEG; ;
     break;}
 case 146:
-#line 982 "parser.y"
+#line 995 "parser.y"
 { yyval.value.id = 0; yyval.value.fValue = yyvsp[-1].val; yyval.value.unit = CSSPrimitiveValue::CSS_RAD; ;
     break;}
 case 147:
-#line 983 "parser.y"
+#line 996 "parser.y"
 { yyval.value.id = 0; yyval.value.fValue = yyvsp[-1].val; yyval.value.unit = CSSPrimitiveValue::CSS_GRAD; ;
     break;}
 case 148:
-#line 984 "parser.y"
+#line 997 "parser.y"
 { yyval.value.id = 0; yyval.value.fValue = yyvsp[-1].val; yyval.value.unit = CSSPrimitiveValue::CSS_MS; ;
     break;}
 case 149:
-#line 985 "parser.y"
+#line 998 "parser.y"
 { yyval.value.id = 0; yyval.value.fValue = yyvsp[-1].val; yyval.value.unit = CSSPrimitiveValue::CSS_S; ;
     break;}
 case 150:
-#line 986 "parser.y"
+#line 999 "parser.y"
 { yyval.value.id = 0; yyval.value.fValue = yyvsp[-1].val; yyval.value.unit = CSSPrimitiveValue::CSS_HZ; ;
     break;}
 case 151:
-#line 987 "parser.y"
+#line 1000 "parser.y"
 { yyval.value.id = 0; yyval.value.fValue = yyvsp[-1].val; yyval.value.unit = CSSPrimitiveValue::CSS_KHZ; ;
     break;}
 case 152:
-#line 988 "parser.y"
+#line 1001 "parser.y"
 { yyval.value.id = 0; yyval.value.fValue = yyvsp[-1].val; yyval.value.unit = CSSPrimitiveValue::CSS_EMS; ;
     break;}
 case 153:
-#line 989 "parser.y"
+#line 1002 "parser.y"
 { yyval.value.id = 0; yyval.value.fValue = yyvsp[-1].val; yyval.value.unit = Value::Q_EMS; ;
     break;}
 case 154:
-#line 990 "parser.y"
+#line 1003 "parser.y"
 { yyval.value.id = 0; yyval.value.fValue = yyvsp[-1].val; yyval.value.unit = CSSPrimitiveValue::CSS_EXS; ;
     break;}
 case 155:
-#line 995 "parser.y"
+#line 1008 "parser.y"
 {
       Function *f = new Function;
       f->name = yyvsp[-4].string;
@@ -2095,7 +2108,7 @@
   ;
     break;}
 case 156:
-#line 1003 "parser.y"
+#line 1016 "parser.y"
 {
       Function *f = new Function;
       f->name = yyvsp[-2].string;
@@ -2106,11 +2119,11 @@
   ;
     break;}
 case 157:
-#line 1018 "parser.y"
+#line 1031 "parser.y"
 { yyval.string = yyvsp[-1].string; ;
     break;}
 case 158:
-#line 1025 "parser.y"
+#line 1038 "parser.y"
 {
 	yyval.rule = 0;
 #ifdef CSS_DEBUG
@@ -2119,7 +2132,7 @@
     ;
     break;}
 case 159:
-#line 1031 "parser.y"
+#line 1044 "parser.y"
 {
 	yyval.rule = 0;
 #ifdef CSS_DEBUG
@@ -2128,7 +2141,7 @@
     ;
     break;}
 case 160:
-#line 1040 "parser.y"
+#line 1053 "parser.y"
 {
 	yyval.rule = 0;
 #ifdef CSS_DEBUG
@@ -2358,6 +2371,6 @@
     }
   return 1;
 }
-#line 1075 "parser.y"
+#line 1088 "parser.y"
 
 
diff --git a/WebCore/khtml/css/parser.y b/WebCore/khtml/css/parser.y
index 542a56e..af88ef5 100644
--- a/WebCore/khtml/css/parser.y
+++ b/WebCore/khtml/css/parser.y
@@ -560,6 +560,12 @@
                 if ( doc )
                     doc->setUsesDescendantRules(true);
             }
+            else if ($2 == CSSSelector::Sibling) {
+                CSSParser *p = static_cast<CSSParser *>(parser);
+                DOM::DocumentImpl *doc = p->document();
+                if (doc)
+                    doc->setUsesSiblingRules(true);
+            }
         } else {
             delete $1;
         }
@@ -770,6 +776,13 @@
         $$->match = CSSSelector::Pseudo;
         $2.lower();
         $$->value = atomicString($2);
+        if ($$->value == "empty" || $$->value == "only-child" ||
+            $$->value == "first-child" || $$->value == "last-child") {
+            CSSParser *p = static_cast<CSSParser *>(parser);
+            DOM::DocumentImpl *doc = p->document();
+            if (doc)
+                doc->setUsesSiblingRules(true);
+        }
     }
     |
     ':' ':' IDENT {