Commit ee5bc0a2 authored by weinig@apple.com's avatar weinig@apple.com

WebCore: Fix for https://bugs.webkit.org/show_bug.cgi?id=29703

Add a function to element to check whether it matches a CSS selector

Reviewed by Dan Bernstein.

Implement Element.webkitMatchesSelector.

* css/CSSSelectorList.cpp:
(WebCore::forEachTagSelector):
(WebCore::forEachSelector):
(WebCore::SelectorNeedsNamespaceResolutionFunctor::operator()):
(WebCore::CSSSelectorList::selectorsNeedNamespaceResolution):
* css/CSSSelectorList.h:
Moved code to iterate the CSSSelectorList and determine if any
selectors need namespace resolution from a static function in
Node.cpp to CSSSelectorList so that it can be used by webkitMatchesSelector
as well as querySelector/querySelectorAll.

* dom/Element.cpp:
(WebCore::Element::webkitMatchesSelector):
* dom/Element.h: 
* dom/Element.idl:
Implement the new function. Handles exceptional cases identically to
querySelector/querySelectorAll.

* dom/Node.cpp:
(WebCore::Node::querySelector):
(WebCore::Node::querySelectorAll):
Moved selectorsNeedNamespaceResolution to CSSSelectorList from here.

LayoutTests: Update tests for https://bugs.webkit.org/show_bug.cgi?id=29703
Add a function to element to check whether it matches a CSS selector

Reviewed by Dan Bernstein.

Add webkitMatchesSelector to SelectorAPI tests.

* fast/dom/SelectorAPI/caseID-almost-strict-expected.txt:
* fast/dom/SelectorAPI/caseID-almost-strict.html:
* fast/dom/SelectorAPI/caseID-expected.txt:
* fast/dom/SelectorAPI/caseID-strict-expected.txt:
* fast/dom/SelectorAPI/caseID-strict.html:
* fast/dom/SelectorAPI/caseID.html:
* fast/dom/SelectorAPI/caseTag-expected.txt:
* fast/dom/SelectorAPI/caseTag.html:
* fast/dom/SelectorAPI/caseTagX-expected.txt:
* fast/dom/SelectorAPI/caseTagX.xhtml:
* fast/dom/SelectorAPI/detached-element-expected.txt:
* fast/dom/SelectorAPI/not-supported-namespace-in-selector-expected.txt:
* fast/dom/SelectorAPI/not-supported-namespace-in-selector.html:
* fast/dom/SelectorAPI/script-tests/detached-element.js:
* fast/dom/SelectorAPI/script-tests/undefined-null-stringify.js:
* fast/dom/SelectorAPI/script-tests/viewless-document.js:
* fast/dom/SelectorAPI/undefined-null-stringify-expected.txt:
* fast/dom/SelectorAPI/viewless-document-expected.txt:
* fast/dom/Window/window-properties-expected.txt:
* fast/dom/domListEnumeration-expected.txt:
* fast/dom/script-tests/domListEnumeration.js:



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@48723 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 4aca7d3b
2009-09-24 Sam Weinig <sam@webkit.org>
Reviewed by Dan Bernstein.
Update tests for https://bugs.webkit.org/show_bug.cgi?id=29703
Add a function to element to check whether it matches a CSS selector
Add webkitMatchesSelector to SelectorAPI tests.
* fast/dom/SelectorAPI/caseID-almost-strict-expected.txt:
* fast/dom/SelectorAPI/caseID-almost-strict.html:
* fast/dom/SelectorAPI/caseID-expected.txt:
* fast/dom/SelectorAPI/caseID-strict-expected.txt:
* fast/dom/SelectorAPI/caseID-strict.html:
* fast/dom/SelectorAPI/caseID.html:
* fast/dom/SelectorAPI/caseTag-expected.txt:
* fast/dom/SelectorAPI/caseTag.html:
* fast/dom/SelectorAPI/caseTagX-expected.txt:
* fast/dom/SelectorAPI/caseTagX.xhtml:
* fast/dom/SelectorAPI/detached-element-expected.txt:
* fast/dom/SelectorAPI/not-supported-namespace-in-selector-expected.txt:
* fast/dom/SelectorAPI/not-supported-namespace-in-selector.html:
* fast/dom/SelectorAPI/script-tests/detached-element.js:
* fast/dom/SelectorAPI/script-tests/undefined-null-stringify.js:
* fast/dom/SelectorAPI/script-tests/viewless-document.js:
* fast/dom/SelectorAPI/undefined-null-stringify-expected.txt:
* fast/dom/SelectorAPI/viewless-document-expected.txt:
* fast/dom/Window/window-properties-expected.txt:
* fast/dom/domListEnumeration-expected.txt:
* fast/dom/script-tests/domListEnumeration.js:
2009-09-24 Oliver Hunt <oliver@apple.com>
Reviewed by NOBODY(rollout)
......
......@@ -2,6 +2,10 @@ PASS document.querySelector('#lower1').textContent is 'lower 1'
PASS document.querySelector('#LOWER2') is null
PASS document.querySelector('#UPPER1').textContent is 'UPPER 1'
PASS document.querySelector('#upper2') is null
PASS document.getElementById('lower1').webkitMatchesSelector('#lower1') is true
PASS document.getElementById('lower2').webkitMatchesSelector('#LOWER2') is false
PASS document.getElementById('UPPER1').webkitMatchesSelector('#UPPER1') is true
PASS document.getElementById('UPPER2').webkitMatchesSelector('#upper2') is false
PASS successfullyParsed is true
TEST COMPLETE
......
......@@ -19,6 +19,11 @@
shouldBe("document.querySelector('#UPPER1').textContent", "'UPPER 1'");
shouldBeNull("document.querySelector('#upper2')");
shouldBeTrue("document.getElementById('lower1').webkitMatchesSelector('#lower1')");
shouldBeFalse("document.getElementById('lower2').webkitMatchesSelector('#LOWER2')");
shouldBeTrue("document.getElementById('UPPER1').webkitMatchesSelector('#UPPER1')");
shouldBeFalse("document.getElementById('UPPER2').webkitMatchesSelector('#upper2')");
var successfullyParsed = true;
</script>
<script src="../../js/resources/js-test-post.js"></script>
......
......@@ -2,6 +2,10 @@ PASS document.querySelector('#lower1').textContent is 'lower 1'
PASS document.querySelector('#LOWER2').textContent is 'lower 2'
PASS document.querySelector('#UPPER1').textContent is 'UPPER 1'
PASS document.querySelector('#upper2').textContent is 'UPPER 2'
PASS document.getElementById('lower1').webkitMatchesSelector('#lower1') is true
PASS document.getElementById('lower2').webkitMatchesSelector('#LOWER2') is true
PASS document.getElementById('UPPER1').webkitMatchesSelector('#UPPER1') is true
PASS document.getElementById('UPPER2').webkitMatchesSelector('#upper2') is true
PASS successfullyParsed is true
TEST COMPLETE
......
......@@ -2,6 +2,10 @@ PASS document.querySelector('#lower1').textContent is 'lower 1'
PASS document.querySelector('#LOWER2') is null
PASS document.querySelector('#UPPER1').textContent is 'UPPER 1'
PASS document.querySelector('#upper2') is null
PASS document.getElementById('lower1').webkitMatchesSelector('#lower1') is true
PASS document.getElementById('lower2').webkitMatchesSelector('#LOWER2') is false
PASS document.getElementById('UPPER1').webkitMatchesSelector('#UPPER1') is true
PASS document.getElementById('UPPER2').webkitMatchesSelector('#upper2') is false
PASS successfullyParsed is true
TEST COMPLETE
......
......@@ -19,6 +19,11 @@
shouldBe("document.querySelector('#UPPER1').textContent", "'UPPER 1'");
shouldBeNull("document.querySelector('#upper2')");
shouldBeTrue("document.getElementById('lower1').webkitMatchesSelector('#lower1')");
shouldBeFalse("document.getElementById('lower2').webkitMatchesSelector('#LOWER2')");
shouldBeTrue("document.getElementById('UPPER1').webkitMatchesSelector('#UPPER1')");
shouldBeFalse("document.getElementById('UPPER2').webkitMatchesSelector('#upper2')");
var successfullyParsed = true;
</script>
<script src="../../js/resources/js-test-post.js"></script>
......
......@@ -18,6 +18,11 @@
shouldBe("document.querySelector('#UPPER1').textContent", "'UPPER 1'");
shouldBe("document.querySelector('#upper2').textContent", "'UPPER 2'");
shouldBeTrue("document.getElementById('lower1').webkitMatchesSelector('#lower1')");
shouldBeTrue("document.getElementById('lower2').webkitMatchesSelector('#LOWER2')");
shouldBeTrue("document.getElementById('UPPER1').webkitMatchesSelector('#UPPER1')");
shouldBeTrue("document.getElementById('UPPER2').webkitMatchesSelector('#upper2')");
var successfullyParsed = true;
</script>
<script src="../../js/resources/js-test-post.js"></script>
......
PASS document.querySelector('div SPAN').textContent is 'lower'
PASS document.querySelector('div p').textContent is 'UPPER'
PASS document.getElementById('lower1').webkitMatchesSelector('div SPAN') is true
PASS document.getElementById('UPPER1').webkitMatchesSelector('div p') is true
PASS successfullyParsed is true
TEST COMPLETE
......
......@@ -14,6 +14,9 @@
shouldBe("document.querySelector('div SPAN').textContent", "'lower'");
shouldBe("document.querySelector('div p').textContent", "'UPPER'");
shouldBeTrue("document.getElementById('lower1').webkitMatchesSelector('div SPAN')");
shouldBeTrue("document.getElementById('UPPER1').webkitMatchesSelector('div p')");
var successfullyParsed = true;
</script>
<script src="../../js/resources/js-test-post.js"></script>
......
PASS document.querySelector('div SPAN') is null
PASS document.getElementById('lower1').webkitMatchesSelector('div SPAN') is false
PASS successfullyParsed is true
TEST COMPLETE
......
......@@ -18,6 +18,8 @@
<![CDATA[
shouldBeNull("document.querySelector('div SPAN')");
shouldBeFalse("document.getElementById('lower1').webkitMatchesSelector('div SPAN')");
var successfullyParsed = true;
]]>
</script>
......
This tests that querySelector and querySelectorAll work with elements that are not in a document yet.
This tests that querySelector, querySelectorAll and matchesSelector (webkitMatchesSelector) work with elements that are not in a document yet.
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
......@@ -11,6 +11,8 @@ PASS root.querySelectorAll('#testId').length is 1
PASS root.querySelectorAll('#testId').item(0) is correctNode
PASS noChild.querySelector('div') is null
PASS noChild.querySelectorAll('div').length is 0
PASS correctNode.webkitMatchesSelector('div') is true
PASS correctNode.webkitMatchesSelector('#testId') is true
PASS successfullyParsed is true
TEST COMPLETE
......
......@@ -2,26 +2,38 @@ This tests that we throw a NAMESPACE_ERR when parsing a selector string for quer
PASS: document.querySelector('bbb|pre') throws: Error: NAMESPACE_ERR: DOM Exception 14
PASS: document.querySelectorAll('bbb|pre') throws: Error: NAMESPACE_ERR: DOM Exception 14
PASS: document.body.webkitMatchesSelector('bbb|pre') throws: Error: NAMESPACE_ERR: DOM Exception 14
PASS: document.querySelector('*|pre') did not throw
PASS: document.querySelectorAll('*|pre') did not throw
PASS: document.body.webkitMatchesSelector('*|pre') did not throw
PASS: document.querySelector('|pre') did not throw
PASS: document.querySelectorAll('|pre') did not throw
PASS: document.body.webkitMatchesSelector('|pre') did not throw
PASS: document.querySelector('div bbb|pre') throws: Error: NAMESPACE_ERR: DOM Exception 14
PASS: document.querySelectorAll('div bbb|pre') throws: Error: NAMESPACE_ERR: DOM Exception 14
PASS: document.body.webkitMatchesSelector('div bbb|pre') throws: Error: NAMESPACE_ERR: DOM Exception 14
PASS: document.querySelector('div *|pre') did not throw
PASS: document.querySelectorAll('div *|pre') did not throw
PASS: document.body.webkitMatchesSelector('div *|pre') did not throw
PASS: document.querySelector('div |pre') did not throw
PASS: document.querySelectorAll('div |pre') did not throw
PASS: document.body.webkitMatchesSelector('div |pre') did not throw
PASS: document.querySelector('[bbb|name=value]') throws: Error: NAMESPACE_ERR: DOM Exception 14
PASS: document.querySelectorAll('[bbb|name=value]') throws: Error: NAMESPACE_ERR: DOM Exception 14
PASS: document.body.webkitMatchesSelector('[bbb|name=value]') throws: Error: NAMESPACE_ERR: DOM Exception 14
PASS: document.querySelector('[*|name=value]') did not throw
PASS: document.querySelectorAll('[*|name=value]') did not throw
PASS: document.body.webkitMatchesSelector('[*|name=value]') did not throw
PASS: document.querySelector('[|name=value]') did not throw
PASS: document.querySelectorAll('[|name=value]') did not throw
PASS: document.body.webkitMatchesSelector('[|name=value]') did not throw
PASS: document.querySelector('div [bbb|name=value]') throws: Error: NAMESPACE_ERR: DOM Exception 14
PASS: document.querySelectorAll('div [bbb|name=value]') throws: Error: NAMESPACE_ERR: DOM Exception 14
PASS: document.body.webkitMatchesSelector('div [bbb|name=value]') throws: Error: NAMESPACE_ERR: DOM Exception 14
PASS: document.querySelector('div [*|name=value]') did not throw
PASS: document.querySelectorAll('div [*|name=value]') did not throw
PASS: document.body.webkitMatchesSelector('div [*|name=value]') did not throw
PASS: document.querySelector('div [|name=value]') did not throw
PASS: document.querySelectorAll('div [|name=value]') did not throw
PASS: document.body.webkitMatchesSelector('div [|name=value]') did not throw
......@@ -33,31 +33,43 @@
{
shouldThrow("document.querySelector('bbb|pre')");
shouldThrow("document.querySelectorAll('bbb|pre')");
shouldThrow("document.body.webkitMatchesSelector('bbb|pre')");
shouldNotThrow("document.querySelector('*|pre')");
shouldNotThrow("document.querySelectorAll('*|pre')");
shouldNotThrow("document.body.webkitMatchesSelector('*|pre')");
shouldNotThrow("document.querySelector('|pre')");
shouldNotThrow("document.querySelectorAll('|pre')");
shouldNotThrow("document.body.webkitMatchesSelector('|pre')");
shouldThrow("document.querySelector('div bbb|pre')");
shouldThrow("document.querySelectorAll('div bbb|pre')");
shouldThrow("document.body.webkitMatchesSelector('div bbb|pre')");
shouldNotThrow("document.querySelector('div *|pre')");
shouldNotThrow("document.querySelectorAll('div *|pre')");
shouldNotThrow("document.body.webkitMatchesSelector('div *|pre')");
shouldNotThrow("document.querySelector('div |pre')");
shouldNotThrow("document.querySelectorAll('div |pre')");
shouldNotThrow("document.body.webkitMatchesSelector('div |pre')");
shouldThrow("document.querySelector('[bbb|name=value]')");
shouldThrow("document.querySelectorAll('[bbb|name=value]')");
shouldThrow("document.body.webkitMatchesSelector('[bbb|name=value]')");
shouldNotThrow("document.querySelector('[*|name=value]')");
shouldNotThrow("document.querySelectorAll('[*|name=value]')");
shouldNotThrow("document.body.webkitMatchesSelector('[*|name=value]')");
shouldNotThrow("document.querySelector('[|name=value]')");
shouldNotThrow("document.querySelectorAll('[|name=value]')");
shouldNotThrow("document.body.webkitMatchesSelector('[|name=value]')");
shouldThrow("document.querySelector('div [bbb|name=value]')");
shouldThrow("document.querySelectorAll('div [bbb|name=value]')");
shouldThrow("document.body.webkitMatchesSelector('div [bbb|name=value]')");
shouldNotThrow("document.querySelector('div [*|name=value]')");
shouldNotThrow("document.querySelectorAll('div [*|name=value]')");
shouldNotThrow("document.body.webkitMatchesSelector('div [*|name=value]')");
shouldNotThrow("document.querySelector('div [|name=value]')");
shouldNotThrow("document.querySelectorAll('div [|name=value]')");
shouldNotThrow("document.body.webkitMatchesSelector('div [|name=value]')");
}
</script>
</head>
......
description(
"This tests that querySelector and querySelectorAll work with elements that are not in a document yet."
"This tests that querySelector, querySelectorAll and matchesSelector (webkitMatchesSelector) work with elements that are not in a document yet."
);
var root = document.createElement('div');
......@@ -19,4 +19,7 @@ shouldBe("root.querySelectorAll('#testId').item(0)", "correctNode");
shouldBeNull("noChild.querySelector('div')");
shouldBe("noChild.querySelectorAll('div').length", "0");
shouldBeTrue("correctNode.webkitMatchesSelector('div')");
shouldBeTrue("correctNode.webkitMatchesSelector('#testId')");
var successfullyParsed = true;
description(
"This tests that the querySelector and querySelectorAll correctly stringify null and undefined to \"null\" and \"undefined\"."
"This tests that the querySelector, querySelectorAll and matchesSelector (webkitMatchesSelector) correctly stringify null and undefined to \"null\" and \"undefined\"."
);
var root = document.createElement('div');
......@@ -17,4 +17,7 @@ shouldBe("document.querySelectorAll(null).item(0)", "nullNode");
shouldBe("document.querySelectorAll(undefined).length", "1");
shouldBe("document.querySelectorAll(undefined).item(0)", "undefinedNode");
shouldBeTrue("nullNode.webkitMatchesSelector(null)");
shouldBeTrue("undefinedNode.webkitMatchesSelector(undefined)");
var successfullyParsed = true;
description(
"This tests that querySelector and querySelectorAll don't crash when used in a viewless document."
"This tests that querySelector, querySelectorAll and matchesSelector (webkitMatchesSelector) don't crash when used in a viewless document."
);
var testDoc = document.implementation.createDocument("http://www.w3.org/1999/xhtml", "html");
......@@ -10,6 +10,7 @@ testDoc.body.appendChild(testDoc.createElement("span")).id = "s2";
testDoc.body.appendChild(testDoc.createElement("div")).className = "d1";
var p1 = testDoc.getElementById("p1");
var s1 = testDoc.getElementById("s1");
var s2 = testDoc.getElementById("s2");
var d1 = testDoc.body.lastChild;
......@@ -19,4 +20,9 @@ shouldBe("testDoc.querySelectorAll('span').item(1)", "s2");
shouldBe("testDoc.querySelector('.d1')", "d1");
shouldBe("testDoc.querySelectorAll('p span').length", "1");
shouldBeTrue("p1.webkitMatchesSelector('p')");
shouldBeTrue("s1.webkitMatchesSelector('p span')");
shouldBeTrue("s2.webkitMatchesSelector('#s2')");
shouldBeTrue("d1.webkitMatchesSelector('.d1')");
var successfullyParsed = true;
This tests that the querySelector and querySelectorAll correctly stringify null and undefined to "null" and "undefined".
This tests that the querySelector, querySelectorAll and matchesSelector (webkitMatchesSelector) correctly stringify null and undefined to "null" and "undefined".
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
......@@ -9,6 +9,8 @@ PASS document.querySelectorAll(null).length is 1
PASS document.querySelectorAll(null).item(0) is nullNode
PASS document.querySelectorAll(undefined).length is 1
PASS document.querySelectorAll(undefined).item(0) is undefinedNode
PASS nullNode.webkitMatchesSelector(null) is true
PASS undefinedNode.webkitMatchesSelector(undefined) is true
PASS successfullyParsed is true
TEST COMPLETE
......
This tests that querySelector and querySelectorAll don't crash when used in a viewless document.
This tests that querySelector, querySelectorAll and matchesSelector (webkitMatchesSelector) don't crash when used in a viewless document.
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
......@@ -8,6 +8,10 @@ PASS testDoc.querySelectorAll('span').length is 2
PASS testDoc.querySelectorAll('span').item(1) is s2
PASS testDoc.querySelector('.d1') is d1
PASS testDoc.querySelectorAll('p span').length is 1
PASS p1.webkitMatchesSelector('p') is true
PASS s1.webkitMatchesSelector('p span') is true
PASS s2.webkitMatchesSelector('#s2') is true
PASS d1.webkitMatchesSelector('.d1') is true
PASS successfullyParsed is true
TEST COMPLETE
......
......@@ -121,6 +121,7 @@ window.Audio.prototype.setAttribute [function]
window.Audio.prototype.setAttributeNS [function]
window.Audio.prototype.setAttributeNode [function]
window.Audio.prototype.setAttributeNodeNS [function]
window.Audio.prototype.webkitMatchesSelector [function]
window.CDATASection [object CDATASectionConstructor]
window.CDATASection.prototype [object CDATASectionPrototype]
window.CDATASection.prototype.ATTRIBUTE_NODE [number]
......@@ -734,6 +735,7 @@ window.Element.prototype.setAttribute [function]
window.Element.prototype.setAttributeNS [function]
window.Element.prototype.setAttributeNode [function]
window.Element.prototype.setAttributeNodeNS [function]
window.Element.prototype.webkitMatchesSelector [function]
window.Entity [object EntityConstructor]
window.Entity.prototype [object EntityPrototype]
window.Entity.prototype.ATTRIBUTE_NODE [number]
......
......@@ -32,7 +32,7 @@ PASS resultArray[2].i is '2'
PASS resultArray[2].item is namedNodeMap.item(2)
[object HTMLFormElement]
PASS resultArray.length is 133
PASS resultArray.length is 134
PASS resultArray[0].i is '0'
PASS resultArray[0].item is document.getElementsByTagName('select')[0]
PASS resultArray[1].i is '1'
......@@ -41,7 +41,7 @@ PASS resultArray[2].i is '2'
PASS resultArray[2].item is document.getElementsByTagName('select')[2]
[object HTMLSelectElement]
PASS resultArray.length is 139
PASS resultArray.length is 140
PASS resultArray[0].i is '0'
PASS resultArray[0].item is document.getElementsByTagName('option')[0]
PASS resultArray[1].i is '1'
......
......@@ -130,7 +130,7 @@ shouldBe("resultArray[2].item", "namedNodeMap.item(2)");
// HTMLFormElement
var htmlFormElement = document.getElementsByTagName('form')[0];
resultArray = iterateList(htmlFormElement);
shouldBe("resultArray.length", "133");
shouldBe("resultArray.length", "134");
shouldBe("resultArray[0].i", "'0'");
shouldBe("resultArray[0].item", "document.getElementsByTagName('select')[0]");
shouldBe("resultArray[1].i", "'1'");
......@@ -141,7 +141,7 @@ shouldBe("resultArray[2].item", "document.getElementsByTagName('select')[2]");
// HTMLSelectElement
var htmlSelectElement = document.getElementsByTagName('select')[0];
resultArray = iterateList(htmlSelectElement);
shouldBe("resultArray.length", "139");
shouldBe("resultArray.length", "140");
shouldBe("resultArray[0].i", "'0'");
shouldBe("resultArray[0].item", "document.getElementsByTagName('option')[0]");
shouldBe("resultArray[1].i", "'1'");
......
2009-09-24 Sam Weinig <sam@webkit.org>
Reviewed by Dan Bernstein.
Fix for https://bugs.webkit.org/show_bug.cgi?id=29703
Add a function to element to check whether it matches a CSS selector
Implement Element.webkitMatchesSelector.
* css/CSSSelectorList.cpp:
(WebCore::forEachTagSelector):
(WebCore::forEachSelector):
(WebCore::SelectorNeedsNamespaceResolutionFunctor::operator()):
(WebCore::CSSSelectorList::selectorsNeedNamespaceResolution):
* css/CSSSelectorList.h:
Moved code to iterate the CSSSelectorList and determine if any
selectors need namespace resolution from a static function in
Node.cpp to CSSSelectorList so that it can be used by webkitMatchesSelector
as well as querySelector/querySelectorAll.
* dom/Element.cpp:
(WebCore::Element::webkitMatchesSelector):
* dom/Element.h:
* dom/Element.idl:
Implement the new function. Handles exceptional cases identically to
querySelector/querySelectorAll.
* dom/Node.cpp:
(WebCore::Node::querySelector):
(WebCore::Node::querySelectorAll):
Moved selectorsNeedNamespaceResolution to CSSSelectorList from here.
2009-09-24 Vitaly Repeshko <vitalyr@chromium.org>
Reviewed by Dimitri Glazkov.
......@@ -89,4 +89,51 @@ void CSSSelectorList::deleteSelectors()
}
}
template <typename Functor>
static bool forEachTagSelector(Functor& functor, CSSSelector* selector)
{
ASSERT(selector);
do {
if (functor(selector))
return true;
if (CSSSelector* simpleSelector = selector->simpleSelector()) {
if (forEachTagSelector(functor, simpleSelector))
return true;
}
} while ((selector = selector->tagHistory()));
return false;
}
template <typename Functor>
static bool forEachSelector(Functor& functor, const CSSSelectorList* selectorList)
{
for (CSSSelector* selector = selectorList->first(); selector; selector = CSSSelectorList::next(selector)) {
if (forEachTagSelector(functor, selector))
return true;
}
return false;
}
class SelectorNeedsNamespaceResolutionFunctor {
public:
bool operator()(CSSSelector* selector)
{
if (selector->hasTag() && selector->m_tag.prefix() != nullAtom && selector->m_tag.prefix() != starAtom)
return true;
if (selector->hasAttribute() && selector->attribute().prefix() != nullAtom && selector->attribute().prefix() != starAtom)
return true;
return false;
}
};
bool CSSSelectorList::selectorsNeedNamespaceResolution()
{
SelectorNeedsNamespaceResolutionFunctor functor;
return forEachSelector(functor, this);
}
} // namespace WebCore
......@@ -31,25 +31,27 @@
namespace WebCore {
class CSSSelectorList : public Noncopyable {
public:
CSSSelectorList() : m_selectorArray(0) { }
~CSSSelectorList();
void adopt(CSSSelectorList& list);
void adoptSelectorVector(Vector<CSSSelector*>& selectorVector);
CSSSelector* first() const { return m_selectorArray ? m_selectorArray : 0; }
static CSSSelector* next(CSSSelector* previous) { return previous->isLastInSelectorList() ? 0 : previous + 1; }
bool hasOneSelector() const { return m_selectorArray ? m_selectorArray->isLastInSelectorList() : false; }
private:
void deleteSelectors();
// End of the array is indicated by m_isLastInSelectorList bit in the last item.
CSSSelector* m_selectorArray;
};
}
#endif
class CSSSelectorList : public Noncopyable {
public:
CSSSelectorList() : m_selectorArray(0) { }
~CSSSelectorList();
void adopt(CSSSelectorList& list);
void adoptSelectorVector(Vector<CSSSelector*>& selectorVector);
CSSSelector* first() const { return m_selectorArray ? m_selectorArray : 0; }
static CSSSelector* next(CSSSelector* previous) { return previous->isLastInSelectorList() ? 0 : previous + 1; }
bool hasOneSelector() const { return m_selectorArray ? m_selectorArray->isLastInSelectorList() : false; }
bool selectorsNeedNamespaceResolution();
private:
void deleteSelectors();
// End of the array is indicated by m_isLastInSelectorList bit in the last item.
CSSSelector* m_selectorArray;
};
} // namespace WebCore
#endif // CSSSelectorList_h
......@@ -28,6 +28,8 @@
#include "AXObjectCache.h"
#include "Attr.h"
#include "CSSParser.h"
#include "CSSSelectorList.h"
#include "CSSStyleSelector.h"
#include "CString.h"
#include "ClientRect.h"
......@@ -1406,6 +1408,39 @@ unsigned Element::childElementCount() const
return count;
}
bool Element::webkitMatchesSelector(const String& selector, ExceptionCode& ec)
{
if (selector.isEmpty()) {
ec = SYNTAX_ERR;
return false;
}
bool strictParsing = !document()->inCompatMode();
CSSParser p(strictParsing);
CSSSelectorList selectorList;
p.parseSelector(selector, document(), selectorList);
if (!selectorList.first()) {
ec = SYNTAX_ERR;
return false;
}
// Throw a NAMESPACE_ERR if the selector includes any namespace prefixes.
if (selectorList.selectorsNeedNamespaceResolution()) {
ec = NAMESPACE_ERR;
return false;
}
CSSStyleSelector::SelectorChecker selectorChecker(document(), strictParsing);
for (CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(selector)) {
if (selectorChecker.checkSelector(selector, this))
return true;
}
return false;
}
KURL Element::getURLAttribute(const QualifiedName& name) const
{
#ifndef NDEBUG
......
......@@ -231,6 +231,8 @@ public:
Element* nextElementSibling() const;
unsigned childElementCount() const;
bool webkitMatchesSelector(const String& selectors, ExceptionCode&);
virtual bool isFormControlElement() const { return false; }
virtual bool isEnabledFormControl() const { return true; }
virtual bool isReadOnlyFormControl() const { return false; }
......
......@@ -110,6 +110,11 @@ module core {
NodeList querySelectorAll(in DOMString selectors)
raises(DOMException);
// WebKit extension, pending specification.
boolean webkitMatchesSelector(in DOMString selectors)
raises(DOMException);
#if !defined(LANGUAGE_COM) || !LANGUAGE_COM
// ElementTraversal API
readonly attribute Element firstElementChild;
......
......@@ -1626,52 +1626,6 @@ PassRefPtr<NodeList> Node::getElementsByClassName(const String& classNames)
return ClassNodeList::create(this, classNames, result.first->second.get());
}
template <typename Functor>
static bool forEachTagSelector(Functor& functor, CSSSelector* selector)
{
ASSERT(selector);
do {
if (functor(selector))
return true;
if (CSSSelector* simpleSelector = selector->simpleSelector()) {
if (forEachTagSelector(functor, simpleSelector))
return true;
}
} while ((selector = selector->tagHistory()));
return false;
}
template <typename Functor>
static bool forEachSelector(Functor& functor, const CSSSelectorList& selectorList)
{
for (CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(selector)) {
if (forEachTagSelector(functor, selector))
return true;
}