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);