First steps towards fixing bug 24021 - pseudo-element styles not accessible / retriev...
authorjberlin@webkit.org <jberlin@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 19 Apr 2010 13:28:27 +0000 (13:28 +0000)
committerjberlin@webkit.org <jberlin@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 19 Apr 2010 13:28:27 +0000 (13:28 +0000)
https://bugs.webkit.org/show_bug.cgi?id=24021

Reviewed by Dave Hyatt.

WebCore:

Allows access to the computed styles for the pseudo-elements through the second argument to getComputedStyle.
This approach does not provide the correct values for 'length' properties and does not work for the ':selection' pseudo-element and will instead return results similiar to those returned by Firefox. This approach also requires waiting until at least one iteration of a hardware accelerated composited animation to return the correct values for the "opacity" and "transform" properties of a pseudo-element associated with the element being animated.
Those values need to be retrieved from the renderer for the pseudo-element as opposed to the cached RenderStyle for the element on which the pseudo-element is defined, which is further complicated by the fact that not all elements have renderers.

Test: fast/css/getComputedStyle/getComputedStyle-with-pseudo-element.html

* WebCore.base.exp:
* css/CSSComputedStyleDeclaration.cpp:
(WebCore::CSSComputedStyleDeclaration::CSSComputedStyleDeclaration):
Parse the and store the pseudo-element specifier from the string provided by the user.
(WebCore::CSSComputedStyleDeclaration::getFontSizeCSSValuePreferringKeyword):
Get the computed style for the pseudo-element if it has been specified.
(WebCore::CSSComputedStyleDeclaration::getPropertyCSSValue):
Get the computed style for the pseudo-element if it has been specified, with a FIXME noting that the values returned for the "opacity" and "transform" properties of a pseudo-element associated with an element being animated and using hardware accelerated compositing will not be correct until after the first iteration of the animation.
(WebCore::CSSComputedStyleDeclaration::length):
Get the computed style for the pseudo-element if it has been specified.
(WebCore::CSSComputedStyleDeclaration::cssPropertyMatches):
Ditto.
* css/CSSComputedStyleDeclaration.h:
(WebCore::computedStyle):
Take into consideration the pseudo-element.

* css/CSSSelector.cpp:
(WebCore::CSSSelector::pseudoId):
Return the PseudoId that corresponds to the given PseudoType. If there is no corresponding PseudoId, returns NOPSEUDO.
(WebCore::nameToPseudoTypeMap):
Create and return the mapping between string names and PseudoTypes.
(WebCore::CSSSelector::parsePseudoType):
Parse and the given string into a PseudoType.
(WebCore::CSSSelector::extractPseudoType):
Refactored to use parsePseudoType.
* css/CSSSelector.h:

* css/CSSStyleSelector.cpp:
(WebCore::CSSStyleSelector::SelectorChecker::checkOneSelector):
Refactored to use pseudoId.

* dom/Element.cpp:
(WebCore::Element::computedStyle):
If the pseudo-element is specified, then return the cached RenderStyle for that PseudoId. Added a FIXME to find the actual renders of the pseudo-elements instead of just the cached RenderStyle of the RenderStyle for the associated element.
* dom/Element.h:
(WebCore::Element::virtualComputedStyle):
Because Element::computedStyle is used so often, don't make it virtual. Instead, provide a virtualComputedStyle method in the Node.h class andmake computedStyle non-virtual. That way the Element version and the Node version of computedStyle will have the same name and look the same at the call site, but the Element version will be more efficient.

* dom/Node.h:
(WebCore::Node::computedStyle):
Ditto.
* dom/Node.cpp:
(WebCore::Node::virtualComputedStyle):
Get the computed style for the pseudo-element if it has been specified.

* page/DOMWindow.cpp:
(WebCore::DOMWindow::getComputedStyle):
Ditto.

LayoutTests:

* fast/css/getComputedStyle/getComputedStyle-with-pseudo-element-expected.txt: Added.
* fast/css/getComputedStyle/getComputedStyle-with-pseudo-element.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@57809 268f45cc-cd09-0410-ab3c-d52691b4dbfc

15 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/css/getComputedStyle/getComputedStyle-with-pseudo-element-expected.txt [new file with mode: 0644]
LayoutTests/fast/css/getComputedStyle/getComputedStyle-with-pseudo-element.html [new file with mode: 0644]
WebCore/ChangeLog
WebCore/WebCore.base.exp
WebCore/css/CSSComputedStyleDeclaration.cpp
WebCore/css/CSSComputedStyleDeclaration.h
WebCore/css/CSSSelector.cpp
WebCore/css/CSSSelector.h
WebCore/css/CSSStyleSelector.cpp
WebCore/dom/Element.cpp
WebCore/dom/Element.h
WebCore/dom/Node.cpp
WebCore/dom/Node.h
WebCore/page/DOMWindow.cpp

index 5ff9f4c..6cbdfae 100644 (file)
@@ -1,3 +1,13 @@
+2010-04-19  Jessie Berlin  <jberlin@webkit.org>
+
+        Reviewed by Dave Hyatt.
+
+        First steps towards fixing bug 24021 - pseudo-element styles not accessible / retrievable via DOM methods.
+        https://bugs.webkit.org/show_bug.cgi?id=24021
+
+        * fast/css/getComputedStyle/getComputedStyle-with-pseudo-element-expected.txt: Added.
+        * fast/css/getComputedStyle/getComputedStyle-with-pseudo-element.html: Added.
+
 2010-04-19  Csaba Osztrogon√°c  <ossy@webkit.org>
 
         [Qt] lacks clipToImageBuffer()
diff --git a/LayoutTests/fast/css/getComputedStyle/getComputedStyle-with-pseudo-element-expected.txt b/LayoutTests/fast/css/getComputedStyle/getComputedStyle-with-pseudo-element-expected.txt
new file mode 100644 (file)
index 0000000..fb89e69
--- /dev/null
@@ -0,0 +1,22 @@
+Test for WebKit bug 24021: pseudo-element styles not accessible / retrievable via DOM methods
+
+
+orem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+
+Middle
+
+There are no pseudo elements defined on this div.
+
+ This should be at full opacity.
+
+PASS Expected 'rgb(165, 42, 42)' for color in the computed style for element with id testFirsts and pseudo-element :first-line and got 'rgb(165, 42, 42)'
+PASS Expected 'rgb(0, 0, 255)' for color in the computed style for element with id testFirsts and pseudo-element :first-letter and got 'rgb(0, 0, 255)'
+PASS Expected 'rgb(0, 0, 255)' for color in the computed style for element with id testFirsts and pseudo-element ::first-letter and got 'rgb(0, 0, 255)'
+PASS Expected 'rgb(0, 0, 255)' for color in the computed style for element with id testFirsts and pseudo-element first-letter and got 'rgb(0, 0, 255)'
+PASS Expected 'rgb(0, 0, 0)' for color in the computed style for element with id testFirsts and pseudo-element null and got 'rgb(0, 0, 0)'
+PASS Expected 'rgb(165, 42, 42)' for color in the computed style for element with id testBeforeAfter and pseudo-element :before and got 'rgb(165, 42, 42)'
+PASS Expected 'rgb(0, 0, 255)' for color in the computed style for element with id testBeforeAfter and pseudo-element :after and got 'rgb(0, 0, 255)'
+PASS Expected 'rgb(165, 42, 42)' for color in the computed style for element with id testNoPseudoElement and pseudo-element null and got 'rgb(165, 42, 42)'
+PASS Expected '' for color in the computed style for element with id testNoPseudoElement and pseudo-element :first-line and got ''
+PASS Expected 'rgb(165, 42, 42)' for color in the computed style for element with id testNoPseudoElement and pseudo-element :garbage and got 'rgb(165, 42, 42)'
+PASS Expected '0.5' for opacity in the computed style for element with id testHardwareAcceleratedCompositing and pseudo-element :before and got '0.5'
diff --git a/LayoutTests/fast/css/getComputedStyle/getComputedStyle-with-pseudo-element.html b/LayoutTests/fast/css/getComputedStyle/getComputedStyle-with-pseudo-element.html
new file mode 100644 (file)
index 0000000..01f709b
--- /dev/null
@@ -0,0 +1,119 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Test for WebKit bug 24021: pseudo-element styles not accessible / retrievable via DOM methods</title>
+    <style type="text/css">
+      #testFirsts:first-line {
+          color: brown;
+      }
+
+      #testFirsts:first-letter {
+          color: blue;
+      }
+
+      #testBeforeAfter::before {
+          content: "This should be brown ";
+          color: brown;
+      }
+
+      #testBeforeAfter::after {
+          content: " and this should be blue";
+          color: blue;
+      }
+
+      #testNoPseudoElement {
+          color: brown;
+      }
+
+      #testHardwareAcceleratedCompositing {
+          width: 100px;
+          height: 100px;
+          opacity: 1.0;
+          background-color: green;
+          -webkit-animation: move 300ms linear;
+          -webkit-transform-style: preserve-3d;
+          -webkit-transform: trasnlate3d(10px, 0, 0);
+      }
+
+     #testHardwareAcceleratedCompositing:before {
+         content: "This should have lower opacity.";
+         opacity: 0.5;
+     }
+
+      @-webkit-keyframes move {
+          from { -webkit-transform: translate3d(10px, 0, 0); }
+          to   { -webkit-transform: translate3d(300px, 0, 0); }
+      }
+
+      .pass {
+          color: green;
+      }
+
+      .fail {
+          color: red;
+      }
+
+    </style>
+    <script type="text/javascript">
+      if (window.layoutTestController)
+          layoutTestController.dumpAsText();
+
+      var tests = [
+        { 'elementId' : 'testFirsts', 'pseudoElement' : ':first-line', 'property' : 'color', 'expectedValue' : 'rgb(165, 42, 42)' },
+        { 'elementId' : 'testFirsts', 'pseudoElement' : ':first-letter', 'property' : 'color', 'expectedValue' : 'rgb(0, 0, 255)' },
+        { 'elementId' : 'testFirsts', 'pseudoElement' : '::first-letter', 'property' : 'color', 'expectedValue' : 'rgb(0, 0, 255)' },
+        { 'elementId' : 'testFirsts', 'pseudoElement' : 'first-letter', 'property' : 'color', 'expectedValue' : 'rgb(0, 0, 255)' },
+        { 'elementId' : 'testFirsts', 'pseudoElement' : null, 'property' : 'color', 'expectedValue' : 'rgb(0, 0, 0)' },
+        { 'elementId' : 'testBeforeAfter', 'pseudoElement' : ':before', 'property' : 'color', 'expectedValue' : 'rgb(165, 42, 42)' },
+        { 'elementId' : 'testBeforeAfter', 'pseudoElement' : ':after', 'property' : 'color', 'expectedValue' : 'rgb(0, 0, 255)' },
+        { 'elementId' : 'testNoPseudoElement', 'pseudoElement' : null, 'property' : 'color', 'expectedValue' : 'rgb(165, 42, 42)' },
+        { 'elementId' : 'testNoPseudoElement', 'pseudoElement' : ':first-line', 'property' : 'color', 'expectedValue' : '' },
+        { 'elementId' : 'testNoPseudoElement', 'pseudoElement' : ':garbage', 'property' : 'color', 'expectedValue' : 'rgb(165, 42, 42)' },
+        { 'elementId' : 'testHardwareAcceleratedCompositing', 'pseudoElement' : ':before', 'property' : 'opacity', 'expectedValue' : '0.5' }
+      ];
+
+      function setupAndRunTests()
+      {
+        if (window.layoutTestController)
+            layoutTestController.waitUntilDone();
+
+        // FIXME: It is currently necessary to run the animation at least once before querying for the style on the pseudo-element will work.
+        document.getElementById("testHardwareAcceleratedCompositing").addEventListener('webkitAnimationEnd', runTests, false);
+      }
+
+      function runTests()
+      {
+        var resultsElement = document.getElementById('results');
+
+        tests.forEach(function(curTest) {
+          var computedStyle = window.getComputedStyle(document.getElementById(curTest.elementId), curTest.pseudoElement);
+          var value = computedStyle[curTest.property];
+          var msg = document.createElement('div');
+          var mainMessage = " Expected '" + curTest.expectedValue + "' for " + curTest.property +
+              " in the computed style for element with id " + curTest.elementId + " and pseudo-element " + curTest.pseudoElement;
+          if (value == curTest.expectedValue)
+              msg.innerHTML = "<span class='pass'>PASS</span>" + mainMessage + " and got '" + value + "'";
+          else
+              msg.innerHTML = "<span class='fail'>FAIL</span>" + mainMessage + " but instead got '" + value + "'";
+          resultsElement.appendChild(msg);
+        });
+
+        if (window.layoutTestController)
+            layoutTestController.notifyDone();
+      }
+    </script>
+  </head>
+  <body onload="setupAndRunTests();">
+    <h3>Test for <a href="https://bugs.webkit.org/show_bug.cgi?id=24021">WebKit bug 24021</a>: pseudo-element styles not accessible / retrievable via DOM methods</h3>
+    <br />
+    <div id="testFirsts">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</div>
+    <br />
+    <div id="testBeforeAfter">Middle</div>
+    <br />
+    <div id="testNoPseudoElement">There are no pseudo elements defined on this div.</div>
+    <br />
+    <div id="testHardwareAcceleratedCompositing"> This should be at full opacity.</div>
+    <br />
+    <div id="results"></div>
+  </body>
+</html>
index c27fce0..27a92d5 100644 (file)
@@ -1,3 +1,65 @@
+2010-04-19  Jessie Berlin  <jberlin@webkit.org>
+
+        Reviewed by Dave Hyatt.
+
+        First steps towards fixing bug 24021 - pseudo-element styles not accessible / retrievable via DOM methods.
+        https://bugs.webkit.org/show_bug.cgi?id=24021
+
+        Allows access to the computed styles for the pseudo-elements through the second argument to getComputedStyle.
+        This approach does not provide the correct values for 'length' properties and does not work for the ':selection' pseudo-element and will instead return results similiar to those returned by Firefox. This approach also requires waiting until at least one iteration of a hardware accelerated composited animation to return the correct values for the "opacity" and "transform" properties of a pseudo-element associated with the element being animated.
+        Those values need to be retrieved from the renderer for the pseudo-element as opposed to the cached RenderStyle for the element on which the pseudo-element is defined, which is further complicated by the fact that not all elements have renderers.
+
+        Test: fast/css/getComputedStyle/getComputedStyle-with-pseudo-element.html
+
+        * WebCore.base.exp:
+        * css/CSSComputedStyleDeclaration.cpp:
+        (WebCore::CSSComputedStyleDeclaration::CSSComputedStyleDeclaration):
+        Parse the and store the pseudo-element specifier from the string provided by the user.
+        (WebCore::CSSComputedStyleDeclaration::getFontSizeCSSValuePreferringKeyword):
+        Get the computed style for the pseudo-element if it has been specified.
+        (WebCore::CSSComputedStyleDeclaration::getPropertyCSSValue):
+        Get the computed style for the pseudo-element if it has been specified, with a FIXME noting that the values returned for the "opacity" and "transform" properties of a pseudo-element associated with an element being animated and using hardware accelerated compositing will not be correct until after the first iteration of the animation.
+        (WebCore::CSSComputedStyleDeclaration::length):
+        Get the computed style for the pseudo-element if it has been specified.
+        (WebCore::CSSComputedStyleDeclaration::cssPropertyMatches):
+        Ditto.
+        * css/CSSComputedStyleDeclaration.h:
+        (WebCore::computedStyle):
+        Take into consideration the pseudo-element.
+
+        * css/CSSSelector.cpp:
+        (WebCore::CSSSelector::pseudoId):
+        Return the PseudoId that corresponds to the given PseudoType. If there is no corresponding PseudoId, returns NOPSEUDO.
+        (WebCore::nameToPseudoTypeMap):
+        Create and return the mapping between string names and PseudoTypes.
+        (WebCore::CSSSelector::parsePseudoType):
+        Parse and the given string into a PseudoType.
+        (WebCore::CSSSelector::extractPseudoType):
+        Refactored to use parsePseudoType.
+        * css/CSSSelector.h:
+
+        * css/CSSStyleSelector.cpp:
+        (WebCore::CSSStyleSelector::SelectorChecker::checkOneSelector):
+        Refactored to use pseudoId.
+
+        * dom/Element.cpp:
+        (WebCore::Element::computedStyle):
+        If the pseudo-element is specified, then return the cached RenderStyle for that PseudoId. Added a FIXME to find the actual renders of the pseudo-elements instead of just the cached RenderStyle of the RenderStyle for the associated element.
+        * dom/Element.h:
+        (WebCore::Element::virtualComputedStyle):
+        Because Element::computedStyle is used so often, don't make it virtual. Instead, provide a virtualComputedStyle method in the Node.h class andmake computedStyle non-virtual. That way the Element version and the Node version of computedStyle will have the same name and look the same at the call site, but the Element version will be more efficient.
+
+        * dom/Node.h:
+        (WebCore::Node::computedStyle):
+        Ditto.
+        * dom/Node.cpp:
+        (WebCore::Node::virtualComputedStyle):
+        Get the computed style for the pseudo-element if it has been specified.
+
+        * page/DOMWindow.cpp:
+        (WebCore::DOMWindow::getComputedStyle):
+        Ditto.
+
 2010-04-18  Simon Hausmann  <simon.hausmann@nokia.com>
 
         Reviewed by Laszlo Gombos.
index ffd22a8..508e8e0 100644 (file)
@@ -480,7 +480,7 @@ __ZN7WebCore25PluginMainThreadScheduler9schedulerEv
 __ZN7WebCore26CSSMutableStyleDeclarationC1Ev
 __ZN7WebCore26NetscapePlugInStreamLoader6createEPNS_5FrameEPNS_32NetscapePlugInStreamLoaderClientE
 __ZN7WebCore26usesTestModeFocusRingColorEv
-__ZN7WebCore27CSSComputedStyleDeclarationC1EN3WTF10PassRefPtrINS_4NodeEEEb
+__ZN7WebCore27CSSComputedStyleDeclarationC1EN3WTF10PassRefPtrINS_4NodeEEEbRKNS_6StringE
 __ZN7WebCore27applicationIsAdobeInstallerEv
 __ZN7WebCore29isCharacterSmartReplaceExemptEib
 __ZN7WebCore29setUsesTestModeFocusRingColorEb
index 68e798f..f1c8dbf 100644 (file)
@@ -31,6 +31,7 @@
 #include "CSSProperty.h"
 #include "CSSPropertyNames.h"
 #include "CSSReflectValue.h"
+#include "CSSSelector.h"
 #include "CSSTimingFunctionValue.h"
 #include "CSSValueList.h"
 #include "Document.h"
@@ -500,10 +501,13 @@ static PassRefPtr<CSSValue> getTimingFunctionValue(const AnimationList* animList
     return list.release();
 }
 
-CSSComputedStyleDeclaration::CSSComputedStyleDeclaration(PassRefPtr<Node> n, bool allowVisitedStyle)
+CSSComputedStyleDeclaration::CSSComputedStyleDeclaration(PassRefPtr<Node> n, bool allowVisitedStyle, const String& pseudoElementName)
     : m_node(n)
     , m_allowVisitedStyle(allowVisitedStyle)
 {
+    unsigned nameWithoutColonsStart = pseudoElementName[0] == ':' ? (pseudoElementName[1] == ':' ? 2 : 1) : 0;
+    m_pseudoElementSpecifier = CSSSelector::pseudoId(CSSSelector::parsePseudoType(
+        AtomicString(pseudoElementName.substring(nameWithoutColonsStart))));
 }
 
 CSSComputedStyleDeclaration::~CSSComputedStyleDeclaration()
@@ -546,7 +550,7 @@ PassRefPtr<CSSValue> CSSComputedStyleDeclaration::getFontSizeCSSValuePreferringK
 
     node->document()->updateLayoutIgnorePendingStylesheets();
 
-    RefPtr<RenderStyle> style = node->computedStyle();
+    RefPtr<RenderStyle> style = node->computedStyle(m_pseudoElementSpecifier);
     if (!style)
         return 0;
 
@@ -664,10 +668,15 @@ PassRefPtr<CSSValue> CSSComputedStyleDeclaration::getPropertyCSSValue(int proper
     RenderObject* renderer = node->renderer();
 
     RefPtr<RenderStyle> style;
-    if (renderer && hasCompositedLayer(renderer) && AnimationController::supportsAcceleratedAnimationOfProperty(static_cast<CSSPropertyID>(propertyID)))
+    if (renderer && hasCompositedLayer(renderer) && AnimationController::supportsAcceleratedAnimationOfProperty(static_cast<CSSPropertyID>(propertyID))) {
         style = renderer->animation()->getAnimatedStyleForRenderer(renderer);
-    else
-       style = node->computedStyle();
+        if (m_pseudoElementSpecifier) {
+            // FIXME: This cached pseudo style will only exist if the animation has been run at least once.
+            style = style->getCachedPseudoStyle(m_pseudoElementSpecifier);
+        }
+    } else
+        style = node->computedStyle(m_pseudoElementSpecifier);
+
     if (!style)
         return 0;
 
@@ -1496,7 +1505,7 @@ unsigned CSSComputedStyleDeclaration::length() const
     if (!node)
         return 0;
 
-    RenderStyle* style = node->computedStyle();
+    RenderStyle* style = node->computedStyle(m_pseudoElementSpecifier);
     if (!style)
         return 0;
 
@@ -1515,7 +1524,7 @@ bool CSSComputedStyleDeclaration::cssPropertyMatches(const CSSProperty* property
 {
     if (property->id() == CSSPropertyFontSize && property->value()->isPrimitiveValue() && m_node) {
         m_node->document()->updateLayoutIgnorePendingStylesheets();
-        RenderStyle* style = m_node->computedStyle();
+        RenderStyle* style = m_node->computedStyle(m_pseudoElementSpecifier);
         if (style && style->fontDescription().keywordSize()) {
             int sizeValue = cssIdentifierForFontSizeKeyword(style->fontDescription().keywordSize());
             CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(property->value());
index 6f962b9..eb93bad 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "CSSStyleDeclaration.h"
 #include "Node.h"
+#include "RenderStyleConstants.h"
 
 namespace WebCore {
 
@@ -33,7 +34,7 @@ enum EUpdateLayout { DoNotUpdateLayout = false, UpdateLayout = true };
 
 class CSSComputedStyleDeclaration : public CSSStyleDeclaration {
 public:
-    friend PassRefPtr<CSSComputedStyleDeclaration> computedStyle(PassRefPtr<Node>, bool allowVisitedStyle = false);
+    friend PassRefPtr<CSSComputedStyleDeclaration> computedStyle(PassRefPtr<Node>, bool allowVisitedStyle, const String& pseudoElementName);
     virtual ~CSSComputedStyleDeclaration();
 
     virtual String cssText() const;
@@ -60,7 +61,7 @@ protected:
     virtual bool cssPropertyMatches(const CSSProperty*) const;
 
 private:
-    CSSComputedStyleDeclaration(PassRefPtr<Node>, bool allowVisitedStyle);
+    CSSComputedStyleDeclaration(PassRefPtr<Node>, bool allowVisitedStyle, const String&);
 
     virtual void setCssText(const String&, ExceptionCode&);
 
@@ -70,12 +71,13 @@ private:
     PassRefPtr<CSSValue> valueForShadow(const ShadowData*, int) const;
 
     RefPtr<Node> m_node;
+    PseudoId m_pseudoElementSpecifier;
     bool m_allowVisitedStyle;
 };
 
-inline PassRefPtr<CSSComputedStyleDeclaration> computedStyle(PassRefPtr<Node> node, bool allowVisitedStyle)
+inline PassRefPtr<CSSComputedStyleDeclaration> computedStyle(PassRefPtr<Node> node,  bool allowVisitedStyle = false, const String& pseudoElementName = String())
 {
-    return adoptRef(new CSSComputedStyleDeclaration(node, allowVisitedStyle));
+    return adoptRef(new CSSComputedStyleDeclaration(node, allowVisitedStyle, pseudoElementName));
 }
 
 } // namespace WebCore
index 9ceb503..af45378 100644 (file)
@@ -28,6 +28,7 @@
 #include "wtf/Assertions.h"
 #include "HTMLNames.h"
 
+#include <wtf/HashMap.h>
 #include <wtf/StdLibExtras.h>
 
 namespace WebCore {
@@ -65,11 +66,148 @@ unsigned int CSSSelector::specificity()
     return s & 0xffffff;
 }
 
-void CSSSelector::extractPseudoType() const
+PseudoId CSSSelector::pseudoId(PseudoType type)
 {
-    if (m_match != PseudoClass && m_match != PseudoElement)
-        return;
+    switch (type) {
+    case PseudoFirstLine:
+        return FIRST_LINE;
+    case PseudoFirstLetter:
+        return FIRST_LETTER;
+    case PseudoSelection:
+        return SELECTION;
+    case PseudoBefore:
+        return BEFORE;
+    case PseudoAfter:
+        return AFTER;
+    case PseudoFileUploadButton:
+        return FILE_UPLOAD_BUTTON;
+#if ENABLE(DATALIST)
+    case PseudoInputListButton:
+        return INPUT_LIST_BUTTON;
+#endif
+    case PseudoInputPlaceholder:
+        return INPUT_PLACEHOLDER;
+    case PseudoSliderThumb:
+        return SLIDER_THUMB;
+    case PseudoSearchCancelButton:
+        return SEARCH_CANCEL_BUTTON;
+    case PseudoSearchDecoration:
+        return SEARCH_DECORATION;
+    case PseudoSearchResultsDecoration:
+        return SEARCH_RESULTS_DECORATION;
+    case PseudoSearchResultsButton:
+        return SEARCH_RESULTS_BUTTON;
+    case PseudoMediaControlsPanel:
+        return MEDIA_CONTROLS_PANEL;
+    case PseudoMediaControlsMuteButton:
+        return MEDIA_CONTROLS_MUTE_BUTTON;
+    case PseudoMediaControlsPlayButton:
+        return MEDIA_CONTROLS_PLAY_BUTTON;
+    case PseudoMediaControlsTimelineContainer:
+        return MEDIA_CONTROLS_TIMELINE_CONTAINER;
+    case PseudoMediaControlsVolumeSliderContainer:
+        return MEDIA_CONTROLS_VOLUME_SLIDER_CONTAINER;
+    case PseudoMediaControlsCurrentTimeDisplay:
+        return MEDIA_CONTROLS_CURRENT_TIME_DISPLAY;
+    case PseudoMediaControlsTimeRemainingDisplay:
+        return MEDIA_CONTROLS_TIME_REMAINING_DISPLAY;
+    case PseudoMediaControlsTimeline:
+        return MEDIA_CONTROLS_TIMELINE;
+    case PseudoMediaControlsVolumeSlider:
+        return MEDIA_CONTROLS_VOLUME_SLIDER;
+    case PseudoMediaControlsSeekBackButton:
+        return MEDIA_CONTROLS_SEEK_BACK_BUTTON;
+    case PseudoMediaControlsSeekForwardButton:
+        return MEDIA_CONTROLS_SEEK_FORWARD_BUTTON;
+    case PseudoMediaControlsRewindButton:
+        return MEDIA_CONTROLS_REWIND_BUTTON;
+    case PseudoMediaControlsReturnToRealtimeButton:
+        return MEDIA_CONTROLS_RETURN_TO_REALTIME_BUTTON;
+    case PseudoMediaControlsToggleClosedCaptions:
+        return MEDIA_CONTROLS_TOGGLE_CLOSED_CAPTIONS_BUTTON;
+    case PseudoMediaControlsStatusDisplay:
+        return MEDIA_CONTROLS_STATUS_DISPLAY;
+    case PseudoMediaControlsFullscreenButton:
+        return MEDIA_CONTROLS_FULLSCREEN_BUTTON;
+    case PseudoScrollbar:
+        return SCROLLBAR;
+    case PseudoScrollbarButton:
+        return SCROLLBAR_BUTTON;
+    case PseudoScrollbarCorner:
+        return SCROLLBAR_CORNER;
+    case PseudoScrollbarThumb:
+        return SCROLLBAR_THUMB;
+    case PseudoScrollbarTrack:
+        return SCROLLBAR_TRACK;
+    case PseudoScrollbarTrackPiece:
+        return SCROLLBAR_TRACK_PIECE;
+    case PseudoResizer:
+        return RESIZER;
+    case PseudoInnerSpinButton:
+        return INNER_SPIN_BUTTON;
+    case PseudoOuterSpinButton:
+        return OUTER_SPIN_BUTTON;
+    case PseudoUnknown:
+    case PseudoEmpty:
+    case PseudoFirstChild:
+    case PseudoFirstOfType:
+    case PseudoLastChild:
+    case PseudoLastOfType:
+    case PseudoOnlyChild:
+    case PseudoOnlyOfType:
+    case PseudoNthChild:
+    case PseudoNthOfType:
+    case PseudoNthLastChild:
+    case PseudoNthLastOfType:
+    case PseudoLink:
+    case PseudoVisited:
+    case PseudoAnyLink:
+    case PseudoAutofill:
+    case PseudoHover:
+    case PseudoDrag:
+    case PseudoFocus:
+    case PseudoActive:
+    case PseudoChecked:
+    case PseudoEnabled:
+    case PseudoFullPageMedia:
+    case PseudoDefault:
+    case PseudoDisabled:
+    case PseudoOptional:
+    case PseudoRequired:
+    case PseudoReadOnly:
+    case PseudoReadWrite:
+    case PseudoValid:
+    case PseudoInvalid:
+    case PseudoIndeterminate:
+    case PseudoTarget:
+    case PseudoLang:
+    case PseudoNot:
+    case PseudoRoot:
+    case PseudoScrollbarBack:
+    case PseudoScrollbarForward:
+    case PseudoWindowInactive:
+    case PseudoCornerPresent:
+    case PseudoDecrement:
+    case PseudoIncrement:
+    case PseudoHorizontal:
+    case PseudoVertical:
+    case PseudoStart:
+    case PseudoEnd:
+    case PseudoDoubleButton:
+    case PseudoSingleButton:
+    case PseudoNoButton:
+        return NOPSEUDO;
+    case PseudoNotParsed:
+        ASSERT_NOT_REACHED();
+        return NOPSEUDO;
+    }
+
+    ASSERT_NOT_REACHED();
+    return NOPSEUDO;
+}
 
+static HashMap<AtomicStringImpl*, CSSSelector::PseudoType>* nameToPseudoTypeMap()
+{
     DEFINE_STATIC_LOCAL(AtomicString, active, ("active"));
     DEFINE_STATIC_LOCAL(AtomicString, after, ("after"));
     DEFINE_STATIC_LOCAL(AtomicString, anyLink, ("-webkit-any-link"));
@@ -161,232 +299,218 @@ void CSSSelector::extractPseudoType() const
     DEFINE_STATIC_LOCAL(AtomicString, noButton, ("no-button"));
     DEFINE_STATIC_LOCAL(AtomicString, cornerPresent, ("corner-present"));
 
+    static HashMap<AtomicStringImpl*, CSSSelector::PseudoType>* nameToPseudoType = 0;
+    if (!nameToPseudoType) {
+        nameToPseudoType = new HashMap<AtomicStringImpl*, CSSSelector::PseudoType>;
+        nameToPseudoType->set(active.impl(), CSSSelector::PseudoActive);
+        nameToPseudoType->set(after.impl(), CSSSelector::PseudoAfter);
+        nameToPseudoType->set(anyLink.impl(), CSSSelector::PseudoAnyLink);
+        nameToPseudoType->set(autofill.impl(), CSSSelector::PseudoAutofill);
+        nameToPseudoType->set(before.impl(), CSSSelector::PseudoBefore);
+        nameToPseudoType->set(checked.impl(), CSSSelector::PseudoChecked);
+        nameToPseudoType->set(fileUploadButton.impl(), CSSSelector::PseudoFileUploadButton);
+        nameToPseudoType->set(defaultString.impl(), CSSSelector::PseudoDefault);
+        nameToPseudoType->set(disabled.impl(), CSSSelector::PseudoDisabled);
+        nameToPseudoType->set(readOnly.impl(), CSSSelector::PseudoReadOnly);
+        nameToPseudoType->set(readWrite.impl(), CSSSelector::PseudoReadWrite);
+        nameToPseudoType->set(valid.impl(), CSSSelector::PseudoValid);
+        nameToPseudoType->set(invalid.impl(), CSSSelector::PseudoInvalid);
+        nameToPseudoType->set(drag.impl(), CSSSelector::PseudoDrag);
+        nameToPseudoType->set(dragAlias.impl(), CSSSelector::PseudoDrag);
+        nameToPseudoType->set(enabled.impl(), CSSSelector::PseudoEnabled);
+        nameToPseudoType->set(empty.impl(), CSSSelector::PseudoEmpty);
+        nameToPseudoType->set(firstChild.impl(), CSSSelector::PseudoFirstChild);
+        nameToPseudoType->set(fullPageMedia.impl(), CSSSelector::PseudoFullPageMedia);
+#if ENABLE(DATALIST)
+        nameToPseudoType->set(inputListButton.impl(), CSSSelector::PseudoInputListButton);
+#endif
+        nameToPseudoType->set(inputPlaceholder.impl(), CSSSelector::PseudoInputPlaceholder);
+        nameToPseudoType->set(lastChild.impl(), CSSSelector::PseudoLastChild);
+        nameToPseudoType->set(lastOfType.impl(), CSSSelector::PseudoLastOfType);
+        nameToPseudoType->set(onlyChild.impl(), CSSSelector::PseudoOnlyChild);
+        nameToPseudoType->set(onlyOfType.impl(), CSSSelector::PseudoOnlyOfType);
+        nameToPseudoType->set(firstLetter.impl(), CSSSelector::PseudoFirstLetter);
+        nameToPseudoType->set(firstLine.impl(), CSSSelector::PseudoFirstLine);
+        nameToPseudoType->set(firstOfType.impl(), CSSSelector::PseudoFirstOfType);
+        nameToPseudoType->set(focus.impl(), CSSSelector::PseudoFocus);
+        nameToPseudoType->set(hover.impl(), CSSSelector::PseudoHover);
+        nameToPseudoType->set(indeterminate.impl(), CSSSelector::PseudoIndeterminate);
+        nameToPseudoType->set(innerSpinButton.impl(), CSSSelector::PseudoInnerSpinButton);
+        nameToPseudoType->set(link.impl(), CSSSelector::PseudoLink);
+        nameToPseudoType->set(lang.impl(), CSSSelector::PseudoLang);
+        nameToPseudoType->set(mediaControlsPanel.impl(), CSSSelector::PseudoMediaControlsPanel);
+        nameToPseudoType->set(mediaControlsMuteButton.impl(), CSSSelector::PseudoMediaControlsMuteButton);
+        nameToPseudoType->set(mediaControlsPlayButton.impl(), CSSSelector::PseudoMediaControlsPlayButton);
+        nameToPseudoType->set(mediaControlsCurrentTimeDisplay.impl(), CSSSelector::PseudoMediaControlsCurrentTimeDisplay);
+        nameToPseudoType->set(mediaControlsTimeRemainingDisplay.impl(), CSSSelector::PseudoMediaControlsTimeRemainingDisplay);
+        nameToPseudoType->set(mediaControlsTimeline.impl(), CSSSelector::PseudoMediaControlsTimeline);
+        nameToPseudoType->set(mediaControlsVolumeSlider.impl(), CSSSelector::PseudoMediaControlsVolumeSlider);
+        nameToPseudoType->set(mediaControlsSeekBackButton.impl(), CSSSelector::PseudoMediaControlsSeekBackButton);
+        nameToPseudoType->set(mediaControlsSeekForwardButton.impl(), CSSSelector::PseudoMediaControlsSeekForwardButton);
+        nameToPseudoType->set(mediaControlsRewindButton.impl(), CSSSelector::PseudoMediaControlsRewindButton);
+        nameToPseudoType->set(mediaControlsReturnToRealtimeButton.impl(), CSSSelector::PseudoMediaControlsReturnToRealtimeButton);
+        nameToPseudoType->set(mediaControlsToggleClosedCaptionsButton.impl(), CSSSelector::PseudoMediaControlsToggleClosedCaptions);
+        nameToPseudoType->set(mediaControlsStatusDisplay.impl(), CSSSelector::PseudoMediaControlsStatusDisplay);
+        nameToPseudoType->set(mediaControlsFullscreenButton.impl(), CSSSelector::PseudoMediaControlsFullscreenButton);
+        nameToPseudoType->set(mediaControlsTimelineContainer.impl(), CSSSelector::PseudoMediaControlsTimelineContainer);
+        nameToPseudoType->set(mediaControlsVolumeSliderContainer.impl(), CSSSelector::PseudoMediaControlsVolumeSliderContainer);
+        nameToPseudoType->set(notStr.impl(), CSSSelector::PseudoNot);
+        nameToPseudoType->set(nthChild.impl(), CSSSelector::PseudoNthChild);
+        nameToPseudoType->set(nthOfType.impl(), CSSSelector::PseudoNthOfType);
+        nameToPseudoType->set(nthLastChild.impl(), CSSSelector::PseudoNthLastChild);
+        nameToPseudoType->set(nthLastOfType.impl(), CSSSelector::PseudoNthLastOfType);
+        nameToPseudoType->set(outerSpinButton.impl(), CSSSelector::PseudoOuterSpinButton);
+        nameToPseudoType->set(root.impl(), CSSSelector::PseudoRoot);
+        nameToPseudoType->set(windowInactive.impl(), CSSSelector::PseudoWindowInactive);
+        nameToPseudoType->set(decrement.impl(), CSSSelector::PseudoDecrement);
+        nameToPseudoType->set(increment.impl(), CSSSelector::PseudoIncrement);
+        nameToPseudoType->set(start.impl(), CSSSelector::PseudoStart);
+        nameToPseudoType->set(end.impl(), CSSSelector::PseudoEnd);
+        nameToPseudoType->set(horizontal.impl(), CSSSelector::PseudoHorizontal);
+        nameToPseudoType->set(vertical.impl(), CSSSelector::PseudoVertical);
+        nameToPseudoType->set(doubleButton.impl(), CSSSelector::PseudoDoubleButton);
+        nameToPseudoType->set(singleButton.impl(), CSSSelector::PseudoSingleButton);
+        nameToPseudoType->set(noButton.impl(), CSSSelector::PseudoNoButton);
+        nameToPseudoType->set(optional.impl(), CSSSelector::PseudoOptional);
+        nameToPseudoType->set(required.impl(), CSSSelector::PseudoRequired);
+        nameToPseudoType->set(resizer.impl(), CSSSelector::PseudoResizer);
+        nameToPseudoType->set(scrollbar.impl(), CSSSelector::PseudoScrollbar);
+        nameToPseudoType->set(scrollbarButton.impl(), CSSSelector::PseudoScrollbarButton);
+        nameToPseudoType->set(scrollbarCorner.impl(), CSSSelector::PseudoScrollbarCorner);
+        nameToPseudoType->set(scrollbarThumb.impl(), CSSSelector::PseudoScrollbarThumb);
+        nameToPseudoType->set(scrollbarTrack.impl(), CSSSelector::PseudoScrollbarTrack);
+        nameToPseudoType->set(scrollbarTrackPiece.impl(), CSSSelector::PseudoScrollbarTrackPiece);
+        nameToPseudoType->set(cornerPresent.impl(), CSSSelector::PseudoCornerPresent);
+        nameToPseudoType->set(searchCancelButton.impl(), CSSSelector::PseudoSearchCancelButton);
+        nameToPseudoType->set(searchDecoration.impl(), CSSSelector::PseudoSearchDecoration);
+        nameToPseudoType->set(searchResultsDecoration.impl(), CSSSelector::PseudoSearchResultsDecoration);
+        nameToPseudoType->set(searchResultsButton.impl(), CSSSelector::PseudoSearchResultsButton);
+        nameToPseudoType->set(selection.impl(), CSSSelector::PseudoSelection);
+        nameToPseudoType->set(sliderThumb.impl(), CSSSelector::PseudoSliderThumb);
+        nameToPseudoType->set(target.impl(), CSSSelector::PseudoTarget);
+        nameToPseudoType->set(visited.impl(), CSSSelector::PseudoVisited);
+    }
+    return nameToPseudoType;
+}
+
+CSSSelector::PseudoType CSSSelector::parsePseudoType(const AtomicString& name)
+{
+    if (name.isNull())
+        return PseudoUnknown;
+    HashMap<AtomicStringImpl*, CSSSelector::PseudoType>* nameToPseudoType = nameToPseudoTypeMap();
+    HashMap<AtomicStringImpl*, CSSSelector::PseudoType>::iterator slot = nameToPseudoType->find(name.impl());
+    return slot == nameToPseudoType->end() ? PseudoUnknown : slot->second;
+}
+
+void CSSSelector::extractPseudoType() const
+{
+    if (m_match != PseudoClass && m_match != PseudoElement)
+        return;
+
+    m_pseudoType = parsePseudoType(m_value);
+
     bool element = false; // pseudo-element
     bool compat = false; // single colon compatbility mode
 
-    m_pseudoType = PseudoUnknown;
-    if (m_value == active)
-        m_pseudoType = PseudoActive;
-    else if (m_value == after) {
-        m_pseudoType = PseudoAfter;
-        element = true;
-        compat = true;
-    } else if (m_value == anyLink)
-        m_pseudoType = PseudoAnyLink;
-    else if (m_value == autofill)
-        m_pseudoType = PseudoAutofill;
-    else if (m_value == before) {
-        m_pseudoType = PseudoBefore;
-        element = true;
-        compat = true;
-    } else if (m_value == checked)
-        m_pseudoType = PseudoChecked;
-    else if (m_value == fileUploadButton) {
-        m_pseudoType = PseudoFileUploadButton;
-        element = true;
-    } else if (m_value == defaultString)
-        m_pseudoType = PseudoDefault;
-    else if (m_value == disabled)
-        m_pseudoType = PseudoDisabled;
-    else if (m_value == readOnly)
-        m_pseudoType = PseudoReadOnly;
-    else if (m_value == readWrite)
-        m_pseudoType = PseudoReadWrite;
-    else if (m_value == valid)
-        m_pseudoType = PseudoValid;
-    else if (m_value == invalid)
-        m_pseudoType = PseudoInvalid;
-    else if (m_value == drag || m_value == dragAlias)
-        m_pseudoType = PseudoDrag;
-    else if (m_value == enabled)
-        m_pseudoType = PseudoEnabled;
-    else if (m_value == empty)
-        m_pseudoType = PseudoEmpty;
-    else if (m_value == firstChild)
-        m_pseudoType = PseudoFirstChild;
-    else if (m_value == fullPageMedia)
-        m_pseudoType = PseudoFullPageMedia;
-    else
-#if ENABLE(DATALIST)
-    if (m_value == inputListButton) {
-        m_pseudoType = PseudoInputListButton;
-        element = true;
-    } else
-#endif
-    if (m_value == inputPlaceholder) {
-        m_pseudoType = PseudoInputPlaceholder;
-        element = true;
-    } else if (m_value == lastChild)
-        m_pseudoType = PseudoLastChild;
-    else if (m_value == lastOfType)
-        m_pseudoType = PseudoLastOfType;
-    else if (m_value == onlyChild)
-        m_pseudoType = PseudoOnlyChild;
-    else if (m_value == onlyOfType)
-        m_pseudoType = PseudoOnlyOfType;
-    else if (m_value == firstLetter) {
-        m_pseudoType = PseudoFirstLetter;
-        element = true;
-        compat = true;
-    } else if (m_value == firstLine) {
-        m_pseudoType = PseudoFirstLine;
-        element = true;
+    switch (m_pseudoType) {
+    case PseudoAfter:
+    case PseudoBefore:
+    case PseudoFirstLetter:
+    case PseudoFirstLine:
         compat = true;
-    } else if (m_value == firstOfType)
-        m_pseudoType = PseudoFirstOfType;
-    else if (m_value == focus)
-        m_pseudoType = PseudoFocus;
-    else if (m_value == hover)
-        m_pseudoType = PseudoHover;
-    else if (m_value == indeterminate)
-        m_pseudoType = PseudoIndeterminate;
-    else if (m_value == innerSpinButton) {
-        m_pseudoType = PseudoInnerSpinButton;
-        element = true;
-    } else if (m_value == link)
-        m_pseudoType = PseudoLink;
-    else if (m_value == lang)
-        m_pseudoType = PseudoLang;
-    else if (m_value == mediaControlsPanel) {
-        m_pseudoType = PseudoMediaControlsPanel;
-        element = true;
-    } else if (m_value == mediaControlsMuteButton) {
-        m_pseudoType = PseudoMediaControlsMuteButton;
-        element = true;
-    } else if (m_value == mediaControlsPlayButton) {
-        m_pseudoType = PseudoMediaControlsPlayButton;
-        element = true;
-    } else if (m_value == mediaControlsCurrentTimeDisplay) {
-        m_pseudoType = PseudoMediaControlsCurrentTimeDisplay;
-        element = true;
-    } else if (m_value == mediaControlsTimeRemainingDisplay) {
-        m_pseudoType = PseudoMediaControlsTimeRemainingDisplay;
-        element = true;
-    } else if (m_value == mediaControlsTimeline) {
-        m_pseudoType = PseudoMediaControlsTimeline;
-        element = true;
-    } else if (m_value == mediaControlsVolumeSlider) {
-        m_pseudoType = PseudoMediaControlsVolumeSlider;
-        element = true;
-    } else if (m_value == mediaControlsSeekBackButton) {
-        m_pseudoType = PseudoMediaControlsSeekBackButton;
-        element = true;
-    } else if (m_value == mediaControlsSeekForwardButton) {
-        m_pseudoType = PseudoMediaControlsSeekForwardButton;
-        element = true;
-    } else if (m_value == mediaControlsRewindButton) {
-        m_pseudoType = PseudoMediaControlsRewindButton;
-        element = true;
-    } else if (m_value == mediaControlsReturnToRealtimeButton) {
-        m_pseudoType = PseudoMediaControlsReturnToRealtimeButton;
-        element = true;
-    } else if (m_value == mediaControlsToggleClosedCaptionsButton) {
-        m_pseudoType = PseudoMediaControlsToggleClosedCaptions;
-        element = true;
-    } else if (m_value == mediaControlsStatusDisplay) {
-        m_pseudoType = PseudoMediaControlsStatusDisplay;
-        element = true;
-    } else if (m_value == mediaControlsFullscreenButton) {
-        m_pseudoType = PseudoMediaControlsFullscreenButton;
-        element = true;
-    } else if (m_value == mediaControlsTimelineContainer) {
-        m_pseudoType = PseudoMediaControlsTimelineContainer;
-        element = true;
-    } else if (m_value == mediaControlsVolumeSliderContainer) {
-        m_pseudoType = PseudoMediaControlsVolumeSliderContainer;
-        element = true;
-    } else if (m_value == notStr)
-        m_pseudoType = PseudoNot;
-    else if (m_value == nthChild)
-        m_pseudoType = PseudoNthChild;
-    else if (m_value == nthOfType)
-        m_pseudoType = PseudoNthOfType;
-    else if (m_value == nthLastChild)
-        m_pseudoType = PseudoNthLastChild;
-    else if (m_value == nthLastOfType)
-        m_pseudoType = PseudoNthLastOfType;
-    else if (m_value == outerSpinButton) {
-        m_pseudoType = PseudoOuterSpinButton;
-        element = true;
-    } else if (m_value == root)
-        m_pseudoType = PseudoRoot;
-    else if (m_value == windowInactive)
-        m_pseudoType = PseudoWindowInactive;
-    else if (m_value == decrement)
-        m_pseudoType = PseudoDecrement;
-    else if (m_value == increment)
-        m_pseudoType = PseudoIncrement;
-    else if (m_value == start)
-        m_pseudoType = PseudoStart;
-    else if (m_value == end)
-        m_pseudoType = PseudoEnd;
-    else if (m_value == horizontal)
-        m_pseudoType = PseudoHorizontal;
-    else if (m_value == vertical)
-        m_pseudoType = PseudoVertical;
-    else if (m_value == doubleButton)
-        m_pseudoType = PseudoDoubleButton;
-    else if (m_value == singleButton)
-        m_pseudoType = PseudoSingleButton;
-    else if (m_value == noButton)
-        m_pseudoType = PseudoNoButton;
-    else if (m_value == optional)
-        m_pseudoType = PseudoOptional;
-    else if (m_value == required)
-        m_pseudoType = PseudoRequired;
-    else if (m_value == scrollbarCorner) {
-        element = true;
-        m_pseudoType = PseudoScrollbarCorner;
-    } else if (m_value == resizer) {
-        element = true;
-        m_pseudoType = PseudoResizer;
-    } else if (m_value == scrollbar) {
-        element = true;
-        m_pseudoType = PseudoScrollbar;
-    } else if (m_value == scrollbarButton) {
-        element = true;
-        m_pseudoType = PseudoScrollbarButton;
-    } else if (m_value == scrollbarCorner) {
-        element = true;
-        m_pseudoType = PseudoScrollbarCorner;
-    } else if (m_value == scrollbarThumb) {
-        element = true;
-        m_pseudoType = PseudoScrollbarThumb;
-    } else if (m_value == scrollbarTrack) {
-        element = true;
-        m_pseudoType = PseudoScrollbarTrack;
-    } else if (m_value == scrollbarTrackPiece) {
-        element = true;
-        m_pseudoType = PseudoScrollbarTrackPiece;
-    } else if (m_value == cornerPresent)
-         m_pseudoType = PseudoCornerPresent;
-    else if (m_value == searchCancelButton) {
-        m_pseudoType = PseudoSearchCancelButton;
-        element = true;
-    } else if (m_value == searchDecoration) {
-        m_pseudoType = PseudoSearchDecoration;
-        element = true;
-    } else if (m_value == searchResultsDecoration) {
-        m_pseudoType = PseudoSearchResultsDecoration;
-        element = true;
-    } else if (m_value == searchResultsButton) {
-        m_pseudoType = PseudoSearchResultsButton;
-        element = true;
-    }  else if (m_value == selection) {
-        m_pseudoType = PseudoSelection;
-        element = true;
-    } else if (m_value == sliderThumb) {
-        m_pseudoType = PseudoSliderThumb;
-        element = true;
-    } else if (m_value == target)
-        m_pseudoType = PseudoTarget;
-    else if (m_value == visited)
-        m_pseudoType = PseudoVisited;
+    case PseudoFileUploadButton:
+    case PseudoInputListButton:
+    case PseudoInputPlaceholder:
+    case PseudoInnerSpinButton:
+    case PseudoMediaControlsPanel:
+    case PseudoMediaControlsMuteButton:
+    case PseudoMediaControlsPlayButton:
+    case PseudoMediaControlsCurrentTimeDisplay:
+    case PseudoMediaControlsTimeRemainingDisplay:
+    case PseudoMediaControlsTimeline:
+    case PseudoMediaControlsVolumeSlider:
+    case PseudoMediaControlsSeekBackButton:
+    case PseudoMediaControlsSeekForwardButton:
+    case PseudoMediaControlsRewindButton:
+    case PseudoMediaControlsReturnToRealtimeButton:
+    case PseudoMediaControlsToggleClosedCaptions:
+    case PseudoMediaControlsStatusDisplay:
+    case PseudoMediaControlsFullscreenButton:
+    case PseudoMediaControlsTimelineContainer:
+    case PseudoMediaControlsVolumeSliderContainer:
+    case PseudoOuterSpinButton:
+    case PseudoResizer:
+    case PseudoScrollbar:
+    case PseudoScrollbarCorner:
+    case PseudoScrollbarButton:
+    case PseudoScrollbarThumb:
+    case PseudoScrollbarTrack:
+    case PseudoScrollbarTrackPiece:
+    case PseudoSearchCancelButton:
+    case PseudoSearchDecoration:
+    case PseudoSearchResultsDecoration:
+    case PseudoSearchResultsButton:
+    case PseudoSelection:
+    case PseudoSliderThumb:
+        element = true;
+        break;
+    case PseudoUnknown:
+    case PseudoEmpty:
+    case PseudoFirstChild:
+    case PseudoFirstOfType:
+    case PseudoLastChild:
+    case PseudoLastOfType:
+    case PseudoOnlyChild:
+    case PseudoOnlyOfType:
+    case PseudoNthChild:
+    case PseudoNthOfType:
+    case PseudoNthLastChild:
+    case PseudoNthLastOfType:
+    case PseudoLink:
+    case PseudoVisited:
+    case PseudoAnyLink:
+    case PseudoAutofill:
+    case PseudoHover:
+    case PseudoDrag:
+    case PseudoFocus:
+    case PseudoActive:
+    case PseudoChecked:
+    case PseudoEnabled:
+    case PseudoFullPageMedia:
+    case PseudoDefault:
+    case PseudoDisabled:
+    case PseudoOptional:
+    case PseudoRequired:
+    case PseudoReadOnly:
+    case PseudoReadWrite:
+    case PseudoValid:
+    case PseudoInvalid:
+    case PseudoIndeterminate:
+    case PseudoTarget:
+    case PseudoLang:
+    case PseudoNot:
+    case PseudoRoot:
+    case PseudoScrollbarBack:
+    case PseudoScrollbarForward:
+    case PseudoWindowInactive:
+    case PseudoCornerPresent:
+    case PseudoDecrement:
+    case PseudoIncrement:
+    case PseudoHorizontal:
+    case PseudoVertical:
+    case PseudoStart:
+    case PseudoEnd:
+    case PseudoDoubleButton:
+    case PseudoSingleButton:
+    case PseudoNoButton:
+    case PseudoNotParsed:
+        break;
+    }
 
     if (m_match == PseudoClass && element) {
-        if (!compat) 
+        if (!compat)
             m_pseudoType = PseudoUnknown;
-        else 
+        else
            m_match = PseudoElement;
     } else if (m_match == PseudoElement && !element)
         m_pseudoType = PseudoUnknown;
index 8d9d64c..f8748c7 100644 (file)
@@ -22,6 +22,7 @@
 #ifndef CSSSelector_h
 #define CSSSelector_h
 
+#include "RenderStyleConstants.h"
 #include "QualifiedName.h"
 #include <wtf/Noncopyable.h>
 #include <wtf/OwnPtr.h>
@@ -194,7 +195,10 @@ namespace WebCore {
                 extractPseudoType();
             return static_cast<PseudoType>(m_pseudoType);
         }
-        
+
+        static PseudoType parsePseudoType(const AtomicString&);
+        static PseudoId pseudoId(PseudoType);
+
         CSSSelector* tagHistory() const { return m_hasRareData ? m_data.m_rareData->m_tagHistory.get() : m_data.m_tagHistory; }
         void setTagHistory(CSSSelector* tagHistory);
 
index 7cb3385..a672c8f 100644 (file)
@@ -2552,132 +2552,16 @@ bool CSSStyleSelector::SelectorChecker::checkOneSelector(CSSSelector* sel, Eleme
         if (!elementStyle && !m_collectRulesOnly)
             return false;
 
-        switch (sel->pseudoType()) {
-            // Pseudo-elements:
-            case CSSSelector::PseudoFirstLine:
-                dynamicPseudo = FIRST_LINE;
-                return true;
-            case CSSSelector::PseudoFirstLetter:
-                dynamicPseudo = FIRST_LETTER;
-                if (Document* doc = e->document())
-                    doc->setUsesFirstLetterRules(true);
-                return true;
-            case CSSSelector::PseudoSelection:
-                dynamicPseudo = SELECTION;
-                return true;
-            case CSSSelector::PseudoBefore:
-                dynamicPseudo = BEFORE;
-                return true;
-            case CSSSelector::PseudoAfter:
-                dynamicPseudo = AFTER;
-                return true;
-            case CSSSelector::PseudoFileUploadButton:
-                dynamicPseudo = FILE_UPLOAD_BUTTON;
-                return true;
-#if ENABLE(DATALIST)
-            case CSSSelector::PseudoInputListButton:
-                dynamicPseudo = INPUT_LIST_BUTTON;
-                return true;
-#endif
-            case CSSSelector::PseudoInputPlaceholder:
-                dynamicPseudo = INPUT_PLACEHOLDER;
-                return true;
-            case CSSSelector::PseudoSliderThumb:
-                dynamicPseudo = SLIDER_THUMB;
-                return true; 
-            case CSSSelector::PseudoSearchCancelButton:
-                dynamicPseudo = SEARCH_CANCEL_BUTTON;
-                return true; 
-            case CSSSelector::PseudoSearchDecoration:
-                dynamicPseudo = SEARCH_DECORATION;
-                return true;
-            case CSSSelector::PseudoSearchResultsDecoration:
-                dynamicPseudo = SEARCH_RESULTS_DECORATION;
-                return true;
-            case CSSSelector::PseudoSearchResultsButton:
-                dynamicPseudo = SEARCH_RESULTS_BUTTON;
-                return true;
-            case CSSSelector::PseudoMediaControlsPanel:
-                dynamicPseudo = MEDIA_CONTROLS_PANEL;
-                return true;
-            case CSSSelector::PseudoMediaControlsMuteButton:
-                dynamicPseudo = MEDIA_CONTROLS_MUTE_BUTTON;
-                return true;
-            case CSSSelector::PseudoMediaControlsPlayButton:
-                dynamicPseudo = MEDIA_CONTROLS_PLAY_BUTTON;
-                return true;
-            case CSSSelector::PseudoMediaControlsTimelineContainer:
-                dynamicPseudo = MEDIA_CONTROLS_TIMELINE_CONTAINER;
-                return true;
-            case CSSSelector::PseudoMediaControlsVolumeSliderContainer:
-                dynamicPseudo = MEDIA_CONTROLS_VOLUME_SLIDER_CONTAINER;
-                return true;
-            case CSSSelector::PseudoMediaControlsCurrentTimeDisplay:
-                dynamicPseudo = MEDIA_CONTROLS_CURRENT_TIME_DISPLAY;
-                return true;
-            case CSSSelector::PseudoMediaControlsTimeRemainingDisplay:
-                dynamicPseudo = MEDIA_CONTROLS_TIME_REMAINING_DISPLAY;
-                return true;
-            case CSSSelector::PseudoMediaControlsTimeline:
-                dynamicPseudo = MEDIA_CONTROLS_TIMELINE;
-                return true;
-            case CSSSelector::PseudoMediaControlsVolumeSlider:
-                dynamicPseudo = MEDIA_CONTROLS_VOLUME_SLIDER;
-                return true;
-            case CSSSelector::PseudoMediaControlsSeekBackButton:
-                dynamicPseudo = MEDIA_CONTROLS_SEEK_BACK_BUTTON;
-                return true;
-            case CSSSelector::PseudoMediaControlsSeekForwardButton:
-                dynamicPseudo = MEDIA_CONTROLS_SEEK_FORWARD_BUTTON;
-                return true;
-            case CSSSelector::PseudoMediaControlsRewindButton:
-                dynamicPseudo = MEDIA_CONTROLS_REWIND_BUTTON;
-                return true;
-            case CSSSelector::PseudoMediaControlsReturnToRealtimeButton:
-                dynamicPseudo = MEDIA_CONTROLS_RETURN_TO_REALTIME_BUTTON;
-                return true;
-            case CSSSelector::PseudoMediaControlsToggleClosedCaptions:
-                dynamicPseudo = MEDIA_CONTROLS_TOGGLE_CLOSED_CAPTIONS_BUTTON;
-                return true;
-            case CSSSelector::PseudoMediaControlsStatusDisplay:
-                dynamicPseudo = MEDIA_CONTROLS_STATUS_DISPLAY;
-                return true;
-            case CSSSelector::PseudoMediaControlsFullscreenButton:
-                dynamicPseudo = MEDIA_CONTROLS_FULLSCREEN_BUTTON;
-                return true;
-            case CSSSelector::PseudoScrollbar:
-                dynamicPseudo = SCROLLBAR;
-                return true;
-            case CSSSelector::PseudoScrollbarButton:
-                dynamicPseudo = SCROLLBAR_BUTTON;
-                return true;
-            case CSSSelector::PseudoScrollbarCorner:
-                dynamicPseudo = SCROLLBAR_CORNER;
-                return true;
-            case CSSSelector::PseudoScrollbarThumb:
-                dynamicPseudo = SCROLLBAR_THUMB;
-                return true;
-            case CSSSelector::PseudoScrollbarTrack:
-                dynamicPseudo = SCROLLBAR_TRACK;
-                return true;
-            case CSSSelector::PseudoScrollbarTrackPiece:
-                dynamicPseudo = SCROLLBAR_TRACK_PIECE;
-                return true;
-            case CSSSelector::PseudoResizer:
-                dynamicPseudo = RESIZER;
-                return true;
-            case CSSSelector::PseudoInnerSpinButton:
-                dynamicPseudo = INNER_SPIN_BUTTON;
-                return true;
-            case CSSSelector::PseudoOuterSpinButton:
-                dynamicPseudo = OUTER_SPIN_BUTTON;
-                return true;
-            case CSSSelector::PseudoUnknown:
-            case CSSSelector::PseudoNotParsed:
-            default:
-                ASSERT_NOT_REACHED();
-                break;
+        PseudoId pseudoId = CSSSelector::pseudoId(sel->pseudoType());
+        if (pseudoId == FIRST_LETTER) {
+            if (Document* document = e->document())
+                document->setUsesFirstLetterRules(true);
+        }
+        if (pseudoId != NOPSEUDO) {
+            dynamicPseudo = pseudoId;
+            return true;
         }
+        ASSERT_NOT_REACHED();
         return false;
     }
     // ### add the rest of the checks...
index b3a9112..3363e95 100644 (file)
@@ -1398,10 +1398,13 @@ void Element::setMinimumSizeForResizing(const IntSize& size)
     ensureRareData()->m_minimumSizeForResizing = size;
 }
 
-RenderStyle* Element::computedStyle()
+RenderStyle* Element::computedStyle(PseudoId pseudoElementSpecifier)
 {
+    // FIXME: Find and use the renderer from the pseudo element instead of the actual element so that the 'length'
+    // properties, which are only known by the renderer because it did the layout, will be correct and so that the
+    // values returned for the ":selection" pseudo-element will be correct.
     if (RenderStyle* usedStyle = renderStyle())
-        return usedStyle;
+        return pseudoElementSpecifier ? usedStyle->getCachedPseudoStyle(pseudoElementSpecifier) : usedStyle;
 
     if (!attached())
         // FIXME: Try to do better than this. Ensure that styleForElement() works for elements that are not in the
@@ -1411,7 +1414,7 @@ RenderStyle* Element::computedStyle()
     ElementRareData* data = ensureRareData();
     if (!data->m_computedStyle)
         data->m_computedStyle = document()->styleForElementIgnoringPendingStylesheets(this);
-    return data->m_computedStyle.get();
+    return pseudoElementSpecifier ? data->m_computedStyle->getCachedPseudoStyle(pseudoElementSpecifier) : data->m_computedStyle.get();
 }
 
 void Element::cancelFocusAppearanceUpdate()
index c363467..eefaeb1 100644 (file)
@@ -201,7 +201,7 @@ public:
     virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
     virtual void recalcStyle(StyleChange = NoChange);
 
-    virtual RenderStyle* computedStyle();
+    RenderStyle* computedStyle(PseudoId = NOPSEUDO);
 
     void dispatchAttrRemovalEvent(Attribute*);
     void dispatchAttrAdditionEvent(Attribute*);
@@ -312,6 +312,7 @@ private:
     virtual const AtomicString& virtualPrefix() const { return prefix(); }
     virtual const AtomicString& virtualLocalName() const { return localName(); }
     virtual const AtomicString& virtualNamespaceURI() const { return namespaceURI(); }
+    virtual RenderStyle* virtualComputedStyle(PseudoId pseudoElementSpecifier = NOPSEUDO) { return computedStyle(pseudoElementSpecifier); }
     
     // cloneNode is private so that non-virtual cloneElementWithChildren and cloneElementWithoutChildren
     // are used instead.
index 50f018b..a04cac9 100644 (file)
@@ -1432,9 +1432,9 @@ void Node::setRenderStyle(PassRefPtr<RenderStyle> s)
         m_renderer->setAnimatableStyle(s); 
 }
 
-RenderStyle* Node::computedStyle()
+RenderStyle* Node::virtualComputedStyle(PseudoId pseudoElementSpecifier)
 {
-    return parent() ? parent()->computedStyle() : 0;
+    return parent() ? parent()->computedStyle(pseudoElementSpecifier) : 0;
 }
 
 int Node::maxCharacterOffset() const
index 3d716fd..7c7f4d1 100644 (file)
@@ -27,6 +27,7 @@
 
 #include "EventTarget.h"
 #include "KURLHash.h"
+#include "RenderStyleConstants.h"
 #include "ScriptWrappable.h"
 #include "TreeShared.h"
 #include <wtf/ListHashSet.h>
@@ -445,7 +446,7 @@ public:
     RenderStyle* renderStyle() const;
     virtual void setRenderStyle(PassRefPtr<RenderStyle>);
 
-    virtual RenderStyle* computedStyle();
+    RenderStyle* computedStyle(PseudoId pseudoElementSpecifier = NOPSEUDO) { return virtualComputedStyle(pseudoElementSpecifier); }
 
     // -----------------------------------------------------------------------------
     // Notification of document structure changes
@@ -599,6 +600,7 @@ private:
     virtual const AtomicString& virtualPrefix() const;
     virtual const AtomicString& virtualLocalName() const;
     virtual const AtomicString& virtualNamespaceURI() const;
+    virtual RenderStyle* virtualComputedStyle(PseudoId = NOPSEUDO);
 
     Element* ancestorElement() const;
 
index 0298941..c46f983 100644 (file)
@@ -1143,13 +1143,12 @@ PassRefPtr<Media> DOMWindow::media() const
     return m_media.get();
 }
 
-PassRefPtr<CSSStyleDeclaration> DOMWindow::getComputedStyle(Element* elt, const String&) const
+PassRefPtr<CSSStyleDeclaration> DOMWindow::getComputedStyle(Element* elt, const String& pseudoElt) const
 {
     if (!elt)
         return 0;
 
-    // FIXME: This needs take pseudo elements into account.
-    return computedStyle(elt);
+    return computedStyle(elt, false, pseudoElt);
 }
 
 PassRefPtr<CSSRuleList> DOMWindow::getMatchedCSSRules(Element* elt, const String&, bool authorOnly) const