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 = ☆ 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 {