Title: [106225] trunk
Revision
106225
Author
commit-qu...@webkit.org
Date
2012-01-30 02:40:23 -0800 (Mon, 30 Jan 2012)

Log Message

The query selector for HTMLContentElement should follow the shadow dom spec.
https://bugs.webkit.org/show_bug.cgi?id=75946

Patch by Shinya Kawanaka <shin...@google.com> on 2012-01-30
Reviewed by Hajime Morita.

Source/WebCore:

Checks the query selector of HTMLContentElement is valid.
If not valid, the selector won't match anything, and shows fallback element.

Test: fast/dom/shadow/content-selector-query.html

* html/shadow/ContentSelectorQuery.cpp:
(WebCore::ContentSelectorQuery::ContentSelectorQuery):
(WebCore::ContentSelectorQuery::isValidSelector):
(WebCore::ContentSelectorQuery::matches):
  When a select query is not valid, any element won't be matched.
(WebCore::validateSubSelector):
(WebCore::validateSelector):
(WebCore::ContentSelectorQuery::validateSelectorList):
  Validate selectors.
* html/shadow/ContentSelectorQuery.h:
* html/shadow/HTMLContentElement.cpp:
(WebCore::HTMLContentElement::isSelectValid):
  Returns true if select attribute is valid.
* html/shadow/HTMLContentElement.h:
* testing/Internals.cpp:
(WebCore::Internals::isValidContentSelect):
* testing/Internals.h:
* testing/Internals.idl:

LayoutTests:

* fast/dom/shadow/content-selector-query-expected.txt: Added.
* fast/dom/shadow/content-selector-query.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (106224 => 106225)


--- trunk/LayoutTests/ChangeLog	2012-01-30 10:39:32 UTC (rev 106224)
+++ trunk/LayoutTests/ChangeLog	2012-01-30 10:40:23 UTC (rev 106225)
@@ -1,3 +1,13 @@
+2012-01-30  Shinya Kawanaka  <shin...@google.com>
+
+        The query selector for HTMLContentElement should follow the shadow dom spec.
+        https://bugs.webkit.org/show_bug.cgi?id=75946
+
+        Reviewed by Hajime Morita.
+
+        * fast/dom/shadow/content-selector-query-expected.txt: Added.
+        * fast/dom/shadow/content-selector-query.html: Added.
+
 2012-01-29  Yuzo Fujishima  <y...@google.com>
 
         [Chromium] Unreviewed test expectation change.

Added: trunk/LayoutTests/fast/dom/shadow/content-selector-query-expected.txt (0 => 106225)


--- trunk/LayoutTests/fast/dom/shadow/content-selector-query-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/dom/shadow/content-selector-query-expected.txt	2012-01-30 10:40:23 UTC (rev 106225)
@@ -0,0 +1,168 @@
+This test checks select attribute of content element is valid.
+
+null
+PASS internals.isValidContentSelect(content) is true
+
+PASS internals.isValidContentSelect(content) is true
+ns|div
+PASS internals.isValidContentSelect(content) is true
+*|div
+PASS internals.isValidContentSelect(content) is true
+|div
+PASS internals.isValidContentSelect(content) is true
+div
+PASS internals.isValidContentSelect(content) is true
+ns|*
+PASS internals.isValidContentSelect(content) is true
+*|*
+PASS internals.isValidContentSelect(content) is true
+|*
+PASS internals.isValidContentSelect(content) is true
+*
+PASS internals.isValidContentSelect(content) is true
+.elem
+PASS internals.isValidContentSelect(content) is true
+p.elem
+PASS internals.isValidContentSelect(content) is true
+foo.elem
+PASS internals.isValidContentSelect(content) is true
+*.right
+PASS internals.isValidContentSelect(content) is true
+#elem
+PASS internals.isValidContentSelect(content) is true
+p#elem
+PASS internals.isValidContentSelect(content) is true
+foo#elem
+PASS internals.isValidContentSelect(content) is true
+*#something
+PASS internals.isValidContentSelect(content) is true
+div[title]
+PASS internals.isValidContentSelect(content) is true
+div[class="example"]
+PASS internals.isValidContentSelect(content) is true
+div[hello="Cleveland"][goodbye="Columbus"]
+PASS internals.isValidContentSelect(content) is true
+div[rel~="copyright"]
+PASS internals.isValidContentSelect(content) is true
+div[href=""
+PASS internals.isValidContentSelect(content) is true
+div[hreflang|="en"]
+PASS internals.isValidContentSelect(content) is true
+div[character=romeo]
+PASS internals.isValidContentSelect(content) is true
+div:link
+PASS internals.isValidContentSelect(content) is true
+div:visited
+PASS internals.isValidContentSelect(content) is true
+div:target
+PASS internals.isValidContentSelect(content) is true
+div:enabled
+PASS internals.isValidContentSelect(content) is true
+div:checked
+PASS internals.isValidContentSelect(content) is true
+div:indeterminate
+PASS internals.isValidContentSelect(content) is true
+div:nth-child(1)
+PASS internals.isValidContentSelect(content) is true
+div:nth-last-child(1)
+PASS internals.isValidContentSelect(content) is true
+div:nth-of-type(1)
+PASS internals.isValidContentSelect(content) is true
+div:nth-last-of-type(1)
+PASS internals.isValidContentSelect(content) is true
+div:first-child
+PASS internals.isValidContentSelect(content) is true
+div:last-child
+PASS internals.isValidContentSelect(content) is true
+div:first-of-type
+PASS internals.isValidContentSelect(content) is true
+div:last-of-type
+PASS internals.isValidContentSelect(content) is true
+div:only-of-type
+PASS internals.isValidContentSelect(content) is true
+div:first-of-type:last-of-type
+PASS internals.isValidContentSelect(content) is true
+div.elem:visited
+PASS internals.isValidContentSelect(content) is true
+*:visited
+PASS internals.isValidContentSelect(content) is true
+div, div
+PASS internals.isValidContentSelect(content) is true
+div:first-of-type, div
+PASS internals.isValidContentSelect(content) is true
+div, div:first-of-type
+PASS internals.isValidContentSelect(content) is true
+div:first-of-type, div:last-of-type
+PASS internals.isValidContentSelect(content) is true
+ div,      div     
+PASS internals.isValidContentSelect(content) is true
+div div
+PASS internals.isValidContentSelect(content) is false
+div > div
+PASS internals.isValidContentSelect(content) is false
+div + div
+PASS internals.isValidContentSelect(content) is false
+div ~ div
+PASS internals.isValidContentSelect(content) is false
+div:not(div)
+PASS internals.isValidContentSelect(content) is false
+div:root
+PASS internals.isValidContentSelect(content) is false
+div:lang(en)
+PASS internals.isValidContentSelect(content) is false
+div::before
+PASS internals.isValidContentSelect(content) is false
+div::after
+PASS internals.isValidContentSelect(content) is false
+div::first-line
+PASS internals.isValidContentSelect(content) is false
+div::first-letter
+PASS internals.isValidContentSelect(content) is false
+div:active
+PASS internals.isValidContentSelect(content) is false
+div:hover
+PASS internals.isValidContentSelect(content) is false
+div:focus
+PASS internals.isValidContentSelect(content) is false
+div div:not(div)
+PASS internals.isValidContentSelect(content) is false
+div:not(div) div
+PASS internals.isValidContentSelect(content) is false
+div span div
+PASS internals.isValidContentSelect(content) is false
+div < div
+PASS internals.isValidContentSelect(content) is false
+div - dvi
+PASS internals.isValidContentSelect(content) is false
+< div
+PASS internals.isValidContentSelect(content) is false
++div
+PASS internals.isValidContentSelect(content) is false
+~div
+PASS internals.isValidContentSelect(content) is false
+div:!
+PASS internals.isValidContentSelect(content) is false
+!:!
+PASS internals.isValidContentSelect(content) is false
+div::!
+PASS internals.isValidContentSelect(content) is false
+div::first_of_type
+PASS internals.isValidContentSelect(content) is false
+pe;ro
+PASS internals.isValidContentSelect(content) is false
+@screen
+PASS internals.isValidContentSelect(content) is false
+@import "style.css"
+PASS internals.isValidContentSelect(content) is false
+div :first-of-type
+PASS internals.isValidContentSelect(content) is false
+div::first-of-type
+PASS internals.isValidContentSelect(content) is false
+ div, ,div
+PASS internals.isValidContentSelect(content) is false
+div ''
+PASS internals.isValidContentSelect(content) is false
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/fast/dom/shadow/content-selector-query.html (0 => 106225)


--- trunk/LayoutTests/fast/dom/shadow/content-selector-query.html	                        (rev 0)
+++ trunk/LayoutTests/fast/dom/shadow/content-selector-query.html	2012-01-30 10:40:23 UTC (rev 106225)
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<p>This test checks select attribute of content element is valid.</p>
+<pre id="console"></pre>
+<div id="container"></div>
+
+<script>
+var container = document.getElementById("container");
+
+var content;
+function test(select, valid) {
+    content = internals.createContentElement(document);
+    if (select != null)
+        content.setAttribute('select', select);
+
+    debug(select);
+    if (valid)
+        shouldBe("internals.isValidContentSelect(content)", "true");
+    else
+        shouldBe("internals.isValidContentSelect(content)", "false");
+}
+
+var dataOfValidCases = [
+    null, '',
+    'ns|div', '*|div', '|div', 'div',
+    'ns|*', '*|*', '|*', '*',
+    '.elem', 'p.elem', 'foo.elem', '*.right',
+    '#elem', 'p#elem', 'foo#elem', '*#something',
+    'div[title]', 'div[class="example"]', 'div[hello="Cleveland"][goodbye="Columbus"]',
+    'div[rel~="copyright"]', 'div[href=""
+    'div[hreflang|="en"]', 'div[character=romeo]',
+    'div:link', 'div:visited', 'div:target', 'div:enabled', 'div:checked',
+    'div:indeterminate', 'div:nth-child(1)', 'div:nth-last-child(1)', 'div:nth-of-type(1)',
+    'div:nth-last-of-type(1)', 'div:first-child', 'div:last-child', 'div:first-of-type',
+    'div:last-of-type', 'div:only-of-type',
+    'div:first-of-type:last-of-type', 'div.elem:visited', '*:visited',
+    'div, div', 'div:first-of-type, div', 'div, div:first-of-type', 'div:first-of-type, div:last-of-type',
+    ' div,      div     ',
+];
+
+var dataOfInvalidCases = [
+    'div div', 'div > div', 'div + div', 'div ~ div',
+    'div:not(div)', 'div:root', 'div:lang(en)',
+    'div::before', 'div::after', 'div::first-line', 'div::first-letter',
+    'div:active', 'div:hover', 'div:focus',
+    'div div:not(div)', 'div:not(div) div', 'div span div',
+    'div < div', 'div - dvi', '< div', '+div', '~div', 'div:!', '!:!', 'div::!', 'div::first_of_type',
+    'pe;ro', '@screen', '@import "style.css"', 'div :first-of-type', 'div::first-of-type',
+    ' div, ,div', 'div \'\''
+]
+
+function doTest() {
+    if (!window.layoutTestController || !window.internals) {
+        return;
+    }
+
+    layoutTestController.dumpAsText();
+
+    for (var i = 0; i < dataOfValidCases.length; ++i) {
+         test(dataOfValidCases[i], true);
+    }
+    for (var i = 0; i < dataOfInvalidCases.length; ++i) {
+         test(dataOfInvalidCases[i], false);
+    }
+}
+
+doTest();
+var successfullyParsed = true;
+</script>
+<script src=""
+</body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (106224 => 106225)


--- trunk/Source/WebCore/ChangeLog	2012-01-30 10:39:32 UTC (rev 106224)
+++ trunk/Source/WebCore/ChangeLog	2012-01-30 10:40:23 UTC (rev 106225)
@@ -1,3 +1,34 @@
+2012-01-30  Shinya Kawanaka  <shin...@google.com>
+
+        The query selector for HTMLContentElement should follow the shadow dom spec.
+        https://bugs.webkit.org/show_bug.cgi?id=75946
+
+        Reviewed by Hajime Morita.
+
+        Checks the query selector of HTMLContentElement is valid.
+        If not valid, the selector won't match anything, and shows fallback element.
+
+        Test: fast/dom/shadow/content-selector-query.html
+
+        * html/shadow/ContentSelectorQuery.cpp:
+        (WebCore::ContentSelectorQuery::ContentSelectorQuery):
+        (WebCore::ContentSelectorQuery::isValidSelector):
+        (WebCore::ContentSelectorQuery::matches):
+          When a select query is not valid, any element won't be matched.
+        (WebCore::validateSubSelector):
+        (WebCore::validateSelector):
+        (WebCore::ContentSelectorQuery::validateSelectorList):
+          Validate selectors.
+        * html/shadow/ContentSelectorQuery.h:
+        * html/shadow/HTMLContentElement.cpp:
+        (WebCore::HTMLContentElement::isSelectValid):
+          Returns true if select attribute is valid.
+        * html/shadow/HTMLContentElement.h:
+        * testing/Internals.cpp:
+        (WebCore::Internals::isValidContentSelect):
+        * testing/Internals.h:
+        * testing/Internals.idl:
+
 2012-01-30  Hans Wennborg  <h...@chromium.org>
 
         Unreviewed, rolling out r106219.

Modified: trunk/Source/WebCore/html/shadow/ContentSelectorQuery.cpp (106224 => 106225)


--- trunk/Source/WebCore/html/shadow/ContentSelectorQuery.cpp	2012-01-30 10:39:32 UTC (rev 106224)
+++ trunk/Source/WebCore/html/shadow/ContentSelectorQuery.cpp	2012-01-30 10:40:23 UTC (rev 106225)
@@ -33,21 +33,30 @@
 
 namespace WebCore {
 
-ContentSelectorQuery::ContentSelectorQuery(HTMLContentElement* element)
+ContentSelectorQuery::ContentSelectorQuery(const HTMLContentElement* element)
     : m_contentElement(element)
     , m_selectorChecker(element->document(), !element->document()->inQuirksMode())
 {
     m_selectorChecker.setCollectingRulesOnly(true);
 
-    if (element->select().isNull() || element->select().isEmpty())
+    if (element->select().isNull() || element->select().isEmpty()) {
+        m_isValidSelector = true;
         return;
+    }
 
     CSSParser parser(true);
     parser.parseSelector(element->select(), element->document(), m_selectorList);
 
-    m_selectors.initialize(m_selectorList);
+    m_isValidSelector = ContentSelectorQuery::validateSelectorList();
+    if (m_isValidSelector)
+        m_selectors.initialize(m_selectorList);
 }
 
+bool ContentSelectorQuery::isValidSelector() const
+{
+    return m_isValidSelector;
+}
+
 bool ContentSelectorQuery::matches(Node* node) const
 {
     ASSERT(node);
@@ -59,10 +68,94 @@
     if (m_contentElement->select().isNull() || m_contentElement->select().isEmpty())
         return true;
 
+    if (!m_isValidSelector)
+        return false;
+
     if (!node->isElementNode())
         return false;
 
     return m_selectors.matches(m_selectorChecker, toElement(node));
 }
 
+static bool validateSubSelector(CSSSelector* selector)
+{
+    switch (selector->m_match) {
+    case CSSSelector::None:
+    case CSSSelector::Id:
+    case CSSSelector::Class:
+    case CSSSelector::Exact:
+    case CSSSelector::Set:
+    case CSSSelector::List:
+    case CSSSelector::Hyphen:
+    case CSSSelector::Contain:
+    case CSSSelector::Begin:
+    case CSSSelector::End:
+        return true;
+    case CSSSelector::PseudoElement:
+        return false;
+    case CSSSelector::PagePseudoClass:
+    case CSSSelector::PseudoClass:
+        break;
+    }
+
+    switch (selector->pseudoType()) {
+    case CSSSelector::PseudoEmpty:
+    case CSSSelector::PseudoLink:
+    case CSSSelector::PseudoVisited:
+    case CSSSelector::PseudoTarget:
+    case CSSSelector::PseudoEnabled:
+    case CSSSelector::PseudoDisabled:
+    case CSSSelector::PseudoChecked:
+    case CSSSelector::PseudoIndeterminate:
+    case CSSSelector::PseudoNthChild:
+    case CSSSelector::PseudoNthLastChild:
+    case CSSSelector::PseudoNthOfType:
+    case CSSSelector::PseudoNthLastOfType:
+    case CSSSelector::PseudoFirstChild:
+    case CSSSelector::PseudoLastChild:
+    case CSSSelector::PseudoFirstOfType:
+    case CSSSelector::PseudoLastOfType:
+    case CSSSelector::PseudoOnlyOfType:
+        return true;
+    default:
+        return false;
+    }
 }
+
+static bool validateSelector(CSSSelector* selector)
+{
+    ASSERT(selector);
+
+    if (!validateSubSelector(selector))
+        return false;
+
+    CSSSelector* prevSubSelector = selector;
+    CSSSelector* subSelector = selector->tagHistory();
+
+    while (subSelector) {
+        if (prevSubSelector->relation() != CSSSelector::SubSelector)
+            return false;
+        if (!validateSubSelector(subSelector))
+            return false;
+
+        prevSubSelector = subSelector;
+        subSelector = subSelector->tagHistory();
+    }
+
+    return true;
+}
+
+bool ContentSelectorQuery::validateSelectorList()
+{
+    if (!m_selectorList.first())
+        return false;
+
+    for (CSSSelector* selector = m_selectorList.first(); selector; selector = m_selectorList.next(selector)) {
+        if (!validateSelector(selector))
+            return false;
+    }
+
+    return true;
+}
+
+}

Modified: trunk/Source/WebCore/html/shadow/ContentSelectorQuery.h (106224 => 106225)


--- trunk/Source/WebCore/html/shadow/ContentSelectorQuery.h	2012-01-30 10:39:32 UTC (rev 106224)
+++ trunk/Source/WebCore/html/shadow/ContentSelectorQuery.h	2012-01-30 10:40:23 UTC (rev 106225)
@@ -46,15 +46,18 @@
 class ContentSelectorQuery {
     WTF_MAKE_NONCOPYABLE(ContentSelectorQuery);
 public:
-    explicit ContentSelectorQuery(HTMLContentElement*);
+    explicit ContentSelectorQuery(const HTMLContentElement*);
 
+    bool isValidSelector() const;
     bool matches(Node*) const;
+private:
+    bool validateSelectorList();
 
-private:
-    HTMLContentElement* m_contentElement;
+    const HTMLContentElement* m_contentElement;
     SelectorDataList m_selectors;
     CSSSelectorList m_selectorList;
     SelectorChecker m_selectorChecker;
+    bool m_isValidSelector;
 };
 
 }

Modified: trunk/Source/WebCore/html/shadow/HTMLContentElement.cpp (106224 => 106225)


--- trunk/Source/WebCore/html/shadow/HTMLContentElement.cpp	2012-01-30 10:39:32 UTC (rev 106224)
+++ trunk/Source/WebCore/html/shadow/HTMLContentElement.cpp	2012-01-30 10:40:23 UTC (rev 106225)
@@ -105,6 +105,12 @@
     return getAttribute(selectAttr);
 }
 
+bool HTMLContentElement::isSelectValid() const
+{
+    ContentSelectorQuery query(this);
+    return query.isValidSelector();
+}
+
 void HTMLContentElement::setSelect(const AtomicString& selectValue)
 {
     setAttribute(selectAttr, selectValue);

Modified: trunk/Source/WebCore/html/shadow/HTMLContentElement.h (106224 => 106225)


--- trunk/Source/WebCore/html/shadow/HTMLContentElement.h	2012-01-30 10:39:32 UTC (rev 106224)
+++ trunk/Source/WebCore/html/shadow/HTMLContentElement.h	2012-01-30 10:40:23 UTC (rev 106225)
@@ -63,6 +63,8 @@
     const ShadowInclusionList* inclusions() const { return m_inclusions.get(); }
     bool hasInclusion() const { return inclusions()->first(); }
 
+    virtual bool isSelectValid() const;
+
 protected:
     HTMLContentElement(const QualifiedName&, Document*);
 

Modified: trunk/Source/WebCore/testing/Internals.cpp (106224 => 106225)


--- trunk/Source/WebCore/testing/Internals.cpp	2012-01-30 10:39:32 UTC (rev 106224)
+++ trunk/Source/WebCore/testing/Internals.cpp	2012-01-30 10:40:23 UTC (rev 106225)
@@ -147,6 +147,16 @@
     return toShadowRoot(shadowRoot)->getElementById(id);
 }
 
+bool Internals::isValidContentSelect(Element* contentElement, ExceptionCode& ec)
+{
+    if (!contentElement || !contentElement->isContentElement()) {
+        ec = INVALID_ACCESS_ERR;
+        return false;
+    }
+
+    return toHTMLContentElement(contentElement)->isSelectValid();
+}
+
 String Internals::elementRenderTreeAsText(Element* element, ExceptionCode& ec)
 {
     if (!element) {

Modified: trunk/Source/WebCore/testing/Internals.h (106224 => 106225)


--- trunk/Source/WebCore/testing/Internals.h	2012-01-30 10:39:32 UTC (rev 106224)
+++ trunk/Source/WebCore/testing/Internals.h	2012-01-30 10:40:23 UTC (rev 106225)
@@ -70,6 +70,7 @@
     String shadowPseudoId(Element*, ExceptionCode&);
     PassRefPtr<Element> createContentElement(Document*, ExceptionCode&);
     Element* getElementByIdInShadowRoot(Node* shadowRoot, const String& id, ExceptionCode&);
+    bool isValidContentSelect(Element* contentElement, ExceptionCode&);
 
 #if ENABLE(INPUT_COLOR)
     void selectColorInColorChooser(Element*, const String& colorValue);

Modified: trunk/Source/WebCore/testing/Internals.idl (106224 => 106225)


--- trunk/Source/WebCore/testing/Internals.idl	2012-01-30 10:39:32 UTC (rev 106224)
+++ trunk/Source/WebCore/testing/Internals.idl	2012-01-30 10:40:23 UTC (rev 106225)
@@ -44,6 +44,7 @@
         DOMString shadowPseudoId(in Element element) raises (DOMException);
         Element createContentElement(in Document document) raises(DOMException);
         Element getElementByIdInShadowRoot(in Node shadowRoot, in DOMString id) raises(DOMException);
+        boolean isValidContentSelect(in Element contentElement) raises(DOMException);
 
 #if defined(ENABLE_INPUT_COLOR) && ENABLE_INPUT_COLOR
         void selectColorInColorChooser(in Element element, in DOMString colorValue);
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to